From ae5a328f055032aa37e1acfc720fdb15c624ad8b Mon Sep 17 00:00:00 2001 From: Juan Diego Gonzalez Date: Tue, 28 Sep 2021 17:42:19 +0000 Subject: [PATCH 001/248] Add Dockerfile for v8 --- docker/Dockerfile | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docker/Dockerfile diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 00000000000..09e50bcc7c2 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,5 @@ +FROM alpine:latest +RUN apk update && \ + apk add curl && \ + curl --location --silent "https://packages.cloudfoundry.org/stable?release=linux64-binary&version=v8&source=github" | tar -zx -C /usr/local/bin && \ + cf --version From d9cef51043f1fea62d81ed12254c4b01f2b41742 Mon Sep 17 00:00:00 2001 From: Brandon Potts Date: Wed, 13 Oct 2021 16:20:39 -0400 Subject: [PATCH 002/248] added a Docker section to the generate-release-notes script Co-authored-by: Juan Diego Gonzalez --- bin/generate-release-notes | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bin/generate-release-notes b/bin/generate-release-notes index 6ade44689b6..f1aad7ebcc5 100755 --- a/bin/generate-release-notes +++ b/bin/generate-release-notes @@ -20,6 +20,13 @@ Binaries - Mac OS X [64 bit](https://packages.cloudfoundry.org/stable?release=macosx64-binary&version=$VERSION&source=github-rel) (tgz) - Windows [64 bit](https://packages.cloudfoundry.org/stable?release=windows64-exe&version=$VERSION&source=github-rel) / [32 bit](https://packages.cloudfoundry.org/stable?release=windows32-exe&version=$VERSION&source=github-rel) (zip) + +Docker +-------- +\`\`\`shell +docker pull cloudfoundry/cli:$VERSION +\`\`\` + Change Log ---------- NOTES From d4961a2e2e48208945595d1bef1d35d6497f527c Mon Sep 17 00:00:00 2001 From: Juan Diego Gonzalez Date: Wed, 13 Oct 2021 21:25:08 +0000 Subject: [PATCH 003/248] go mod tidy Co-authored-by: Juan Diego Gonzalez --- go.mod | 10 ---------- go.sum | 55 +------------------------------------------------------ 2 files changed, 1 insertion(+), 64 deletions(-) diff --git a/go.mod b/go.mod index f059b2303bd..d67598838c6 100644 --- a/go.mod +++ b/go.mod @@ -18,30 +18,21 @@ require ( code.cloudfoundry.org/ykk v0.0.0-20170424192843-e4df4ce2fd4d github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect github.com/SermoDigital/jose v0.9.2-0.20161205224733-f6df55f235c2 - github.com/akavel/rsrc v0.10.2 // indirect - github.com/apoydence/eachers v0.0.0-20181020210610-23942921fe77 // indirect github.com/blang/semver v3.5.1+incompatible github.com/bmatcuk/doublestar v1.3.1 // indirect github.com/charlievieth/fs v0.0.0-20170613215519-7dc373669fa1 // indirect github.com/cloudfoundry/bosh-cli v5.5.1+incompatible github.com/cloudfoundry/bosh-utils v0.0.0-20180315210917-c6a922e299b8 // indirect - github.com/cloudfoundry/noaa v2.1.1-0.20190110210640-5ce49363dfa6+incompatible // indirect - github.com/cloudfoundry/sonde-go v0.0.0-20171206171820-b33733203bb4 // indirect github.com/cppforlife/go-patch v0.1.0 // indirect github.com/cyphar/filepath-securejoin v0.2.1 github.com/docker/distribution v2.6.0-rc.1.0.20171109224904-e5b5e44386f7+incompatible github.com/docker/docker v1.4.2-0.20171120205147-9de84a78d76e // indirect - github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d // indirect - github.com/elazarl/goproxy/ext v0.0.0-20200809112317-0581fc3aee2d // indirect github.com/fatih/color v1.5.1-0.20170926111411-5df930a27be2 github.com/fsnotify/fsnotify v1.5.1 // indirect - github.com/gogo/protobuf v1.3.1 // indirect github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 - github.com/gorilla/websocket v1.2.1-0.20171201014301-b89020ee79b8 // indirect github.com/jessevdk/go-flags v1.4.1-0.20181221193153-c0795c8afcf4 github.com/kr/pty v1.1.1 github.com/lunixbochs/vtclean v1.0.0 - github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e // indirect github.com/mattn/go-colorable v0.1.0 github.com/mattn/go-isatty v0.0.3 // indirect github.com/mattn/go-runewidth v0.0.5-0.20181218000649-703b5e6b11ae @@ -52,7 +43,6 @@ require ( github.com/onsi/gomega v1.10.5 github.com/opencontainers/go-digest v1.0.0-rc1 // indirect github.com/pkg/errors v0.9.1 - github.com/poy/eachers v0.0.0-20181020210610-23942921fe77 // indirect github.com/sabhiram/go-gitignore v0.0.0-20171017070213-362f9845770f github.com/sajari/fuzzy v1.0.0 github.com/sirupsen/logrus v1.2.0 diff --git a/go.sum b/go.sum index 1d6e3e51268..4bcafc592e3 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,6 @@ code.cloudfoundry.org/lager v1.1.1-0.20191008172124-a9afc05ee5be h1:rnGRgbKlOPKb code.cloudfoundry.org/lager v1.1.1-0.20191008172124-a9afc05ee5be/go.mod h1:O2sS7gKP3HM2iemG+EnwvyNQK7pTSC6Foi4QiMp9sSk= code.cloudfoundry.org/rfc5424 v0.0.0-20180905210152-236a6d29298a h1:8rqv2w8xEceNwckcF5ONeRt0qBHlh5bnNfFnYTrZbxs= code.cloudfoundry.org/rfc5424 v0.0.0-20180905210152-236a6d29298a/go.mod h1:tkZo8GtzBjySJ7USvxm4E36lNQw1D3xM6oKHGqdaAJ4= -code.cloudfoundry.org/tlsconfig v0.0.0-20200131000646-bbe0f8da39b3 h1:2Qal+q+tw/DmDOoJBWwDCPE3lIJNj/1o7oMkkb2c5SI= -code.cloudfoundry.org/tlsconfig v0.0.0-20200131000646-bbe0f8da39b3/go.mod h1:eTbFJpyXRGuFVyg5+oaj9B2eIbIc+0/kZjH8ftbtdew= code.cloudfoundry.org/tlsconfig v0.0.0-20210615191307-5d92ef3894a7 h1:5N6M1WbWH3bknkX80Q/s7eEo5odqjixLAW79Zrrbqu0= code.cloudfoundry.org/tlsconfig v0.0.0-20210615191307-5d92ef3894a7/go.mod h1:CKI5CV+3MlfcohVSuU3FxXubFyC52lYJGMLnZ2ltvks= code.cloudfoundry.org/ykk v0.0.0-20170424192843-e4df4ce2fd4d h1:M+zXqtXJqcsmpL76aU0tdl1ho23eYa4axYoM4gD62UA= @@ -35,11 +33,7 @@ github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/SermoDigital/jose v0.9.2-0.20161205224733-f6df55f235c2 h1:koK7z0nSsRiRiBWwa+E714Puh+DO+ZRdIyAXiXzL+lg= github.com/SermoDigital/jose v0.9.2-0.20161205224733-f6df55f235c2/go.mod h1:ARgCUhI1MHQH+ONky/PAtmVHQrP5JlGY0F3poXOp/fA= -github.com/akavel/rsrc v0.10.2 h1:Zxm8V5eI1hW4gGaYsJQUhxpjkENuG91ki8B4zCrvEsw= -github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= -github.com/apoydence/eachers v0.0.0-20181020210610-23942921fe77 h1:afT88tB6u9JCKQZVAAaa9ICz/uGn5Uw9ekn6P22mYKM= -github.com/apoydence/eachers v0.0.0-20181020210610-23942921fe77/go.mod h1:bXvGk6IkT1Agy7qzJ+DjIw/SJ1AaB3AvAuMDVV+Vkoo= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bmatcuk/doublestar v1.3.1 h1:rT8rxDPsavp9G+4ZULzqhhUSaI/OPsTZNG88Z3i0xvY= @@ -55,10 +49,6 @@ github.com/cloudfoundry/bosh-cli v5.5.1+incompatible h1:a4SP5/+ZlnfrMefIhklrw7Uk github.com/cloudfoundry/bosh-cli v5.5.1+incompatible/go.mod h1:rzIB+e1sn7wQL/TJ54bl/FemPKRhXby5BIMS3tLuWFM= github.com/cloudfoundry/bosh-utils v0.0.0-20180315210917-c6a922e299b8 h1:x6vZOZ7rlvGro4GKDg0DaQz2za8Q6GjhVoB7vH6BZ2I= github.com/cloudfoundry/bosh-utils v0.0.0-20180315210917-c6a922e299b8/go.mod h1:JCrKwetZGjxbfq1U139TZuXDBfdGLtjOEAfxMWKV/QM= -github.com/cloudfoundry/noaa v2.1.1-0.20190110210640-5ce49363dfa6+incompatible h1:kXzOyUKUpx5VMNXKU5v8I1lGqcdU2DYYCYtBrfILmLI= -github.com/cloudfoundry/noaa v2.1.1-0.20190110210640-5ce49363dfa6+incompatible/go.mod h1:5LmacnptvxzrTvMfL9+EJhgkUfIgcwI61BVSTh47ECo= -github.com/cloudfoundry/sonde-go v0.0.0-20171206171820-b33733203bb4 h1:cWfya7mo/zbnwYVio6eWGsFJHqYw4/k/uhwIJ1eqRPI= -github.com/cloudfoundry/sonde-go v0.0.0-20171206171820-b33733203bb4/go.mod h1:GS0pCHd7onIsewbw8Ue9qa9pZPv2V88cUZDttK6KzgI= github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= github.com/cppforlife/go-patch v0.1.0 h1:I0fT+gFTSW4xWwvaTaUUVjr9xxjNXJ4naGc01BeQjwY= github.com/cppforlife/go-patch v0.1.0/go.mod h1:67a7aIi94FHDZdoeGSJRRFDp66l9MhaAG1yGxpUoFD8= @@ -72,33 +62,20 @@ github.com/docker/distribution v2.6.0-rc.1.0.20171109224904-e5b5e44386f7+incompa github.com/docker/docker v1.4.2-0.20171120205147-9de84a78d76e h1:M+/1NNHE/mg+RUox/04+rZoahJVklPfs6xZFECVnxso= github.com/docker/docker v1.4.2-0.20171120205147-9de84a78d76e/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/drewolson/testflight v1.0.0/go.mod h1:t9oKuuEohRGLb80SWX+uxJHuhX98B7HnojqtW+Ryq30= -github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d h1:rtM8HsT3NG37YPjz8sYSbUSdElP9lUsQENYzJDZDUBE= -github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= -github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= -github.com/elazarl/goproxy/ext v0.0.0-20200809112317-0581fc3aee2d h1:st1tmvy+4duoRj+RaeeJoECWCWM015fBtf/4aR+hhqk= -github.com/elazarl/goproxy/ext v0.0.0-20200809112317-0581fc3aee2d/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.5.1-0.20170926111411-5df930a27be2 h1:lSx4zNYRd54K1yU6E/Uak9R4GqTMt7L44QU8aT1W3Go= github.com/fatih/color v1.5.1-0.20170926111411-5df930a27be2/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.0 h1:NO5hkcB+srp1x6QmwvNZLeaOgbM8cmBTN32THzjvu2k= -github.com/fsnotify/fsnotify v1.5.0/go.mod h1:BX0DCEr5pT4jm2CnQdVP1lFV521fcCNcyEeNp4DQQDk= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -111,10 +88,7 @@ github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:od github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.2.1-0.20171201014301-b89020ee79b8 h1:bct7UIBzlnefiBVOokxvELF3E2rQcJwdMWQ0MKmu/nY= -github.com/gorilla/websocket v1.2.1-0.20171201014301-b89020ee79b8/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/grpc-ecosystem/grpc-gateway v1.14.0 h1:CI8J2kQ4VC2vS3lhVQa+5lMpwCyqyNCAWAPHGMGszQw= github.com/grpc-ecosystem/grpc-gateway v1.14.0/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= @@ -124,7 +98,6 @@ github.com/jessevdk/go-flags v1.4.1-0.20181221193153-c0795c8afcf4 h1:xKkUL6QBojw github.com/jessevdk/go-flags v1.4.1-0.20181221193153-c0795c8afcf4/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/joefitzgerald/rainbow-reporter v0.1.0 h1:AuMG652zjdzI0YCCnXAqATtRBpGXMcAnrajcaTrSeuo= github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -136,12 +109,9 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.0.0-20160504234017-7cafcd837844/go.mod h1:sjUstKUATFIcff4qlB53Kml0wQPtJVc/3fWrmuUmcfA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-colorable v0.1.0 h1:v2XXALHHh6zHfYTJ+cSkwtyffnaOyR1MXaA91mTrb8o= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI= @@ -154,7 +124,6 @@ github.com/moby/moby v1.4.2-0.20171120205147-9de84a78d76e h1:6+Fs/ljqCOuJ4Ie4VUB github.com/moby/moby v1.4.2-0.20171120205147-9de84a78d76e/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -163,9 +132,7 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= -github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4= github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= @@ -180,17 +147,13 @@ github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7 github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= -github.com/pivotal-cf/brokerapi/v7 v7.2.0 h1:LL/OS3H2p+K30YG1ppB7Fr1YFQ669My00icLkxYqdwU= github.com/pivotal-cf/brokerapi/v7 v7.2.0/go.mod h1:5QRQ8vJmav91F+AvY5NA/QoDOq70XgBVxXKUK4N/cNE= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/poy/eachers v0.0.0-20181020210610-23942921fe77 h1:SNdqPRvRsVmYR0gKqFvrUKhFizPJ6yDiGQ++VAJIoDg= -github.com/poy/eachers v0.0.0-20181020210610-23942921fe77/go.mod h1:x1vqpbcMW9T/KRcQ4b48diSiSVtYgvwQ5xzDByEg4WE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/sabhiram/go-gitignore v0.0.0-20171017070213-362f9845770f h1:FQZgA673tRGrrXIP/OPMO69g81ow4XsKlN/DLH8pSic= github.com/sabhiram/go-gitignore v0.0.0-20171017070213-362f9845770f/go.mod h1:b18R55ulyQ/h3RaWyloPyER7fWQVZvimKKhnI5OfrJQ= @@ -205,8 +168,8 @@ github.com/square/certstrap v1.2.0/go.mod h1:CUHqV+fxJW0Y5UQFnnbYwQ7bpKXO1AKbic9 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -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 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/tedsuo/ifrit v0.0.0-20191009134036-9a97d0632f00 h1:mujcChM89zOHwgZBBNr5WZ77mBXP1yR+gLThGCYZgAg= github.com/tedsuo/ifrit v0.0.0-20191009134036-9a97d0632f00/go.mod h1:eyZnKCc955uh98WQvzOm0dgAeLnf2O0Rz0LPoC5ze+0= @@ -225,8 +188,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= -golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -235,7 +196,6 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -252,10 +212,8 @@ golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -280,8 +238,6 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirSiguP9Q/veMtkYyf0o8= -golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -289,24 +245,17 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912 h1:uCLL3g5wH2xjxVREVuAbP9JM5PPKjRbXKRa6IBjkzmU= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -315,13 +264,11 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200609164405-eb789aa7ce50/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 3ab9fb7e5635de8c4a90c70499e11d04465a6946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Diego=20Gonz=C3=A1lez?= <25335192+jdgonzaleza@users.noreply.github.com> Date: Tue, 9 Nov 2021 11:00:36 -0500 Subject: [PATCH 004/248] [Bugfix] CF security-groups returns 414 error (#2229) Implementing batcher in `cf security-group` command Co-authored-by: Sebastian Gil --- actor/v7action/security_group.go | 24 ++++++---- actor/v7action/security_group_test.go | 66 +++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 8 deletions(-) diff --git a/actor/v7action/security_group.go b/actor/v7action/security_group.go index 04f567003cc..73099a307ee 100644 --- a/actor/v7action/security_group.go +++ b/actor/v7action/security_group.go @@ -10,6 +10,7 @@ import ( "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/batcher" "code.cloudfoundry.org/cli/util/lookuptable" ) @@ -323,16 +324,23 @@ func getSecurityGroupSpaces(actor Actor, stagingSpaceGUIDs []string, runningSpac associatedSpaceGuids = append(associatedSpaceGuids, stagingSpaceGUIDs...) var securityGroupSpaces []SecurityGroupSpace + var spaces []resources.Space + var includes ccv3.IncludedResources + if len(associatedSpaceGuids) > 0 { - spaces, includes, newWarnings, err := actor.CloudControllerClient.GetSpaces(ccv3.Query{ - Key: ccv3.GUIDFilter, - Values: associatedSpaceGuids, - }, ccv3.Query{ - Key: ccv3.Include, - Values: []string{"organization"}, + ccv3Warnings, err := batcher.RequestByGUID(associatedSpaceGuids, func(guids []string) (ccv3.Warnings, error) { + batchSpaces, batchIncludes, newWarnings, err := actor.CloudControllerClient.GetSpaces(ccv3.Query{ + Key: ccv3.GUIDFilter, + Values: guids, + }, ccv3.Query{ + Key: ccv3.Include, + Values: []string{"organization"}, + }) + spaces = append(spaces, batchSpaces...) + includes.Organizations = append(includes.Organizations, batchIncludes.Organizations...) + return newWarnings, err }) - - warnings = newWarnings + warnings = ccv3Warnings if err != nil { return securityGroupSpaces, warnings, err } diff --git a/actor/v7action/security_group_test.go b/actor/v7action/security_group_test.go index f17aba80d58..02aa8f691d6 100644 --- a/actor/v7action/security_group_test.go +++ b/actor/v7action/security_group_test.go @@ -14,6 +14,7 @@ import ( "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/batcher" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) @@ -639,7 +640,72 @@ var _ = Describe("Security Group Actions", func() { Expect(executeErr).To(MatchError(expectedError)) }) }) + }) + When("there are many spaces associated", func() { + const batches = 10 + JustBeforeEach(func() { + securityGroupSummaries, _, _ = actor.GetSecurityGroups() + }) + BeforeEach(func() { + var ( + securityGroups []resources.SecurityGroup + manySpaces []resources.Space + manySpacesGUIDs []string + ) + + for i := 0; i < batcher.BatchSize*batches; i++ { + guid := fmt.Sprintf("some-space-guid-%d", i) + manySpaces = append(manySpaces, resources.Space{ + Name: fmt.Sprintf("some-space-%d", i), + GUID: guid, + Relationships: resources.Relationships{ + constant.RelationshipTypeOrganization: resources.Relationship{GUID: "org-guid-1"}, + }, + }) + manySpacesGUIDs = append(manySpacesGUIDs, guid) + } + + securityGroups = append(securityGroups, resources.SecurityGroup{ + GUID: "some-security-group-guid-1", + Name: "some-security-group-1", + Rules: []resources.Rule{{ + Destination: "127.0.0.1", + Description: &description, + Ports: &port, + Protocol: "tcp", + }}, + RunningGloballyEnabled: &trueVal, + StagingGloballyEnabled: &falseVal, + RunningSpaceGUIDs: manySpacesGUIDs, + }) + + for b := 0; b < batches; b++ { + fakeCloudControllerClient.GetSpacesReturns( + manySpaces[:batcher.BatchSize], + ccv3.IncludedResources{ + Organizations: []resources.Organization{{GUID: "some-org-guid"}}, + }, + ccv3.Warnings{"get-spaces-warnings"}, + nil, + ) + manySpaces = manySpaces[batcher.BatchSize:] + } + fakeCloudControllerClient.GetSecurityGroupsReturns( + securityGroups, + ccv3.Warnings{"get-spaces-warnings"}, + nil, + ) + }) + + It("makes mutiple calls to get spaces", func() { + Expect(len(securityGroupSummaries)).To(Equal(1)) + Expect(fakeCloudControllerClient.GetSpacesCallCount()).To(Equal(batches)) + Expect(fakeCloudControllerClient.GetSpacesArgsForCall(0)). + NotTo(Equal(fakeCloudControllerClient.GetSpacesArgsForCall(1))) + }) + }) + }) Describe("GetSecurityGroup", func() { From 5ed753dd2aa8dc85dd244780815a343095c74426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Diego=20Gonz=C3=A1lez?= <25335192+jdgonzaleza@users.noreply.github.com> Date: Wed, 10 Nov 2021 15:51:24 -0500 Subject: [PATCH 005/248] [Feature] support HTTP/2 cf command (#2230) [reason] Renaming "protocol" column to "app-protocol" in the destination table of the cf route command Co-authored-by: Hector Calderon --- command/v7/route_command.go | 2 +- command/v7/route_command_test.go | 2 +- integration/v7/isolated/route_command_test.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/command/v7/route_command.go b/command/v7/route_command.go index 5c89398e8ff..86dbc69ba6b 100644 --- a/command/v7/route_command.go +++ b/command/v7/route_command.go @@ -116,7 +116,7 @@ func (cmd RouteCommand) displayDestinations(route resources.Route, appMap map[st cmd.UI.TranslateText("app"), cmd.UI.TranslateText("process"), cmd.UI.TranslateText("port"), - cmd.UI.TranslateText("protocol"), + cmd.UI.TranslateText("app-protocol"), }, } diff --git a/command/v7/route_command_test.go b/command/v7/route_command_test.go index 2d616beafb4..d209c055bac 100644 --- a/command/v7/route_command_test.go +++ b/command/v7/route_command_test.go @@ -220,7 +220,7 @@ var _ = Describe("route Command", func() { Expect(testUI.Out).To(Say(`protocol:\s+http`)) Expect(testUI.Out).To(Say(`\n`)) Expect(testUI.Out).To(Say(`Destinations:`)) - Expect(testUI.Out).To(Say(`\s+app\s+process\s+port\s+protocol`)) + Expect(testUI.Out).To(Say(`\s+app\s+process\s+port\s+app-protocol`)) Expect(testUI.Out).To(Say(`\s+app-name\s+web\s+8080\s+http1`)) Expect(testUI.Out).To(Say(`\s+other-app-name\s+web\s+1337\s+http2`)) diff --git a/integration/v7/isolated/route_command_test.go b/integration/v7/isolated/route_command_test.go index 4e8d109d2fc..85d50275c44 100644 --- a/integration/v7/isolated/route_command_test.go +++ b/integration/v7/isolated/route_command_test.go @@ -119,7 +119,7 @@ var _ = Describe("route command", func() { Eventually(session).Should(Say(`protocol:\s+http`)) Eventually(session).Should(Say(`\n`)) Eventually(session).Should(Say(`Destinations:`)) - Eventually(session).Should(Say(`\s+app\s+process\s+port\s+protocol`)) + Eventually(session).Should(Say(`\s+app\s+process\s+port\s+app-protocol`)) Eventually(session).Should(Exit(0)) }) @@ -167,7 +167,7 @@ var _ = Describe("route command", func() { Eventually(session).Should(Say(`protocol:\s+tcp`)) Eventually(session).Should(Say(`\n`)) Eventually(session).Should(Say(`Destinations:`)) - Eventually(session).Should(Say(`\s+app\s+process\s+port\s+protocol`)) + Eventually(session).Should(Say(`\s+app\s+process\s+port\s+app-protocol`)) Eventually(session).Should(Exit(0)) }) From eadbc48264d6d61708150483630fa595c7d022ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Diego=20Gonz=C3=A1lez?= <25335192+jdgonzaleza@users.noreply.github.com> Date: Fri, 12 Nov 2021 14:45:50 -0500 Subject: [PATCH 006/248] [Feature] Rename flag to app-protocol in map-route (#2231) Currently the cli already has a flag named destination-protocol and in order to have consistency we need to rename it to app-protocol Co-authored-by: Hector Calderon --- command/v7/map_route_command.go | 20 ++++++++-------- command/v7/map_route_command_test.go | 24 +++++++++---------- .../v7/isolated/map_route_command_test.go | 10 ++++---- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/command/v7/map_route_command.go b/command/v7/map_route_command.go index 4224b40741c..fbeba5b12ed 100644 --- a/command/v7/map_route_command.go +++ b/command/v7/map_route_command.go @@ -8,11 +8,11 @@ import ( type MapRouteCommand struct { BaseCommand - RequiredArgs flag.AppDomain `positional-args:"yes"` - Hostname string `long:"hostname" short:"n" description:"Hostname for the HTTP route (required for shared domains)"` - Path flag.V7RoutePath `long:"path" description:"Path for the HTTP route"` - Port int `long:"port" description:"Port for the TCP route (default: random port)"` - DestinationProtocol string `long:"destination-protocol" description:"[Beta flag, subject to change] Protocol for the route destination (default: http1). Only applied to HTTP routes"` + RequiredArgs flag.AppDomain `positional-args:"yes"` + Hostname string `long:"hostname" short:"n" description:"Hostname for the HTTP route (required for shared domains)"` + Path flag.V7RoutePath `long:"path" description:"Path for the HTTP route"` + Port int `long:"port" description:"Port for the TCP route (default: random port)"` + AppProtocol string `long:"app-protocol" description:"[Beta flag, subject to change] Protocol for the route destination (default: http1). Only applied to HTTP routes"` relatedCommands interface{} `related_commands:"create-route, routes, unmap-route"` } @@ -20,7 +20,7 @@ type MapRouteCommand struct { func (cmd MapRouteCommand) Usage() string { return ` Map an HTTP route: - CF_NAME map-route APP_NAME DOMAIN [--hostname HOSTNAME] [--path PATH] [--destination-protocol PROTOCOL] + CF_NAME map-route APP_NAME DOMAIN [--hostname HOSTNAME] [--path PATH] [--app-protocol PROTOCOL] Map a TCP route: CF_NAME map-route APP_NAME DOMAIN [--port PORT]` @@ -31,7 +31,7 @@ func (cmd MapRouteCommand) Examples() string { CF_NAME map-route my-app example.com # example.com CF_NAME map-route my-app example.com --hostname myhost # myhost.example.com CF_NAME map-route my-app example.com --hostname myhost --path foo # myhost.example.com/foo -CF_NAME map-route my-app example.com --hostname myhost --destination-protocol http2 # myhost.example.com +CF_NAME map-route my-app example.com --hostname myhost --app-protocol http2 # myhost.example.com CF_NAME map-route my-app example.com --port 5000 # example.com:5000` } @@ -88,14 +88,14 @@ func (cmd MapRouteCommand) Execute(args []string) error { cmd.UI.DisplayOK() } - if cmd.DestinationProtocol != "" { + if cmd.AppProtocol != "" { cmd.UI.DisplayTextWithFlavor("Mapping route {{.URL}} to app {{.AppName}} with protocol {{.Protocol}} in org {{.OrgName}} / space {{.SpaceName}} as {{.User}}...", map[string]interface{}{ "URL": route.URL, "AppName": cmd.RequiredArgs.App, "User": user.Name, "SpaceName": cmd.Config.TargetedSpace().Name, "OrgName": cmd.Config.TargetedOrganization().Name, - "Protocol": cmd.DestinationProtocol, + "Protocol": cmd.AppProtocol, }) } else { @@ -121,7 +121,7 @@ func (cmd MapRouteCommand) Execute(args []string) error { cmd.UI.DisplayOK() return nil } - warnings, err = cmd.Actor.MapRoute(route.GUID, app.GUID, cmd.DestinationProtocol) + warnings, err = cmd.Actor.MapRoute(route.GUID, app.GUID, cmd.AppProtocol) cmd.UI.DisplayWarnings(warnings) if err != nil { return err diff --git a/command/v7/map_route_command_test.go b/command/v7/map_route_command_test.go index 00e8154a7a8..6cef92a3f7f 100644 --- a/command/v7/map_route_command_test.go +++ b/command/v7/map_route_command_test.go @@ -53,10 +53,10 @@ var _ = Describe("map-route Command", func() { spaceGUID = "some-space-guid" cmd = MapRouteCommand{ - RequiredArgs: flag.AppDomain{App: appName, Domain: domain}, - Hostname: hostname, - Path: flag.V7RoutePath{Path: path}, - DestinationProtocol: "http2", + RequiredArgs: flag.AppDomain{App: appName, Domain: domain}, + Hostname: hostname, + Path: flag.V7RoutePath{Path: path}, + AppProtocol: "http2", BaseCommand: BaseCommand{ UI: testUI, Config: fakeConfig, @@ -372,10 +372,10 @@ var _ = Describe("map-route Command", func() { Expect(actualPort).To(Equal(cmd.Port)) Expect(fakeActor.MapRouteCallCount()).To(Equal(1)) - actualRouteGUID, actualAppGUID, actualDestinationProtocol := fakeActor.MapRouteArgsForCall(0) + actualRouteGUID, actualAppGUID, actualAppProtocol := fakeActor.MapRouteArgsForCall(0) Expect(actualRouteGUID).To(Equal("route-guid")) Expect(actualAppGUID).To(Equal("app-guid")) - Expect(actualDestinationProtocol).To(Equal("http2")) + Expect(actualAppProtocol).To(Equal("http2")) }) }) @@ -411,10 +411,10 @@ var _ = Describe("map-route Command", func() { Expect(actualPort).To(Equal(cmd.Port)) Expect(fakeActor.MapRouteCallCount()).To(Equal(1)) - actualRouteGUID, actualAppGUID, actualDestinationProtocol := fakeActor.MapRouteArgsForCall(0) + actualRouteGUID, actualAppGUID, actualAppProtocol := fakeActor.MapRouteArgsForCall(0) Expect(actualRouteGUID).To(Equal("route-guid")) Expect(actualAppGUID).To(Equal("app-guid")) - Expect(actualDestinationProtocol).To(Equal("http2")) + Expect(actualAppProtocol).To(Equal("http2")) }) }) }) @@ -534,10 +534,10 @@ var _ = Describe("map-route Command", func() { Expect(actualPort).To(Equal(cmd.Port)) Expect(fakeActor.MapRouteCallCount()).To(Equal(1)) - actualRouteGUID, actualAppGUID, actualDestinationProtocol := fakeActor.MapRouteArgsForCall(0) + actualRouteGUID, actualAppGUID, actualAppProtocol := fakeActor.MapRouteArgsForCall(0) Expect(actualRouteGUID).To(Equal("route-guid")) Expect(actualAppGUID).To(Equal("app-guid")) - Expect(actualDestinationProtocol).To(Equal("http2")) + Expect(actualAppProtocol).To(Equal("http2")) }) }) @@ -573,10 +573,10 @@ var _ = Describe("map-route Command", func() { Expect(actualPort).To(Equal(cmd.Port)) Expect(fakeActor.MapRouteCallCount()).To(Equal(1)) - actualRouteGUID, actualAppGUID, actualDestinationProtocol := fakeActor.MapRouteArgsForCall(0) + actualRouteGUID, actualAppGUID, actualAppProtocol := fakeActor.MapRouteArgsForCall(0) Expect(actualRouteGUID).To(Equal("route-guid")) Expect(actualAppGUID).To(Equal("app-guid")) - Expect(actualDestinationProtocol).To(Equal("http2")) + Expect(actualAppProtocol).To(Equal("http2")) }) }) }) diff --git a/integration/v7/isolated/map_route_command_test.go b/integration/v7/isolated/map_route_command_test.go index ea734b65fb9..3aaec9b04e5 100644 --- a/integration/v7/isolated/map_route_command_test.go +++ b/integration/v7/isolated/map_route_command_test.go @@ -29,7 +29,7 @@ var _ = Describe("map-route command", func() { Eventually(session).Should(Say(`USAGE:`)) Eventually(session).Should(Say(`Map an HTTP route:\n`)) - Eventually(session).Should(Say(`cf map-route APP_NAME DOMAIN \[--hostname HOSTNAME\] \[--path PATH\] \[--destination-protocol PROTOCOL\]\n`)) + Eventually(session).Should(Say(`cf map-route APP_NAME DOMAIN \[--hostname HOSTNAME\] \[--path PATH\] \[--app-protocol PROTOCOL\]\n`)) Eventually(session).Should(Say(`Map a TCP route:\n`)) Eventually(session).Should(Say(`cf map-route APP_NAME DOMAIN \[--port PORT]\n`)) Eventually(session).Should(Say(`\n`)) @@ -38,7 +38,7 @@ var _ = Describe("map-route command", func() { Eventually(session).Should(Say(`cf map-route my-app example.com # example.com`)) Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost # myhost.example.com`)) Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost --path foo # myhost.example.com/foo`)) - Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost --destination-protocol http2 # myhost.example.com`)) + Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost --app-protocol http2 # myhost.example.com`)) Eventually(session).Should(Say(`cf map-route my-app example.com --port 5000 # example.com:5000`)) Eventually(session).Should(Say(`\n`)) @@ -46,7 +46,7 @@ var _ = Describe("map-route command", func() { Eventually(session).Should(Say(`--hostname, -n\s+Hostname for the HTTP route \(required for shared domains\)`)) Eventually(session).Should(Say(`--path\s+Path for the HTTP route`)) Eventually(session).Should(Say(`--port\s+Port for the TCP route \(default: random port\)`)) - Eventually(session).Should(Say(`--destination-protocol\s+\[Beta flag, subject to change\] Protocol for the route destination \(default: http1\). Only applied to HTTP routes`)) + Eventually(session).Should(Say(`--app-protocol\s+\[Beta flag, subject to change\] Protocol for the route destination \(default: http1\). Only applied to HTTP routes`)) Eventually(session).Should(Say(`\n`)) @@ -133,7 +133,7 @@ var _ = Describe("map-route command", func() { }) It("maps the route to an app", func() { - session := helpers.CF("map-route", appName, domainName, "--hostname", route.Host, "--destination-protocol", "http2") + session := helpers.CF("map-route", appName, domainName, "--hostname", route.Host, "--app-protocol", "http2") Eventually(session).Should(Say(`Mapping route %s.%s to app %s with protocol http2 in org %s / space %s as %s\.\.\.`, hostName, domainName, appName, orgName, spaceName, userName)) Eventually(session).Should(Say(`OK`)) @@ -227,7 +227,7 @@ var _ = Describe("map-route command", func() { }) It("maps the route to an app", func() { - session := helpers.CF("map-route", appName, domainName, "--hostname", hostName, "--destination-protocol", "http2") + session := helpers.CF("map-route", appName, domainName, "--hostname", hostName, "--app-protocol", "http2") Eventually(session).Should(Say(`Creating route %s.%s for org %s / space %s as %s\.\.\.`, hostName, domainName, orgName, spaceName, userName)) Eventually(session).Should(Say(`OK`)) Eventually(session).Should(Say(`Mapping route %s.%s to app %s with protocol http2 in org %s / space %s as %s\.\.\.`, hostName, domainName, appName, orgName, spaceName, userName)) From 276d2e620d2e306cdb19268f7f000813d0881a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Diego=20Gonz=C3=A1lez?= <25335192+jdgonzaleza@users.noreply.github.com> Date: Mon, 22 Nov 2021 17:30:51 -0500 Subject: [PATCH 007/248] [Feature] Add app-protocol to cf routes command output (#2234) Currently we do not show the app-protocol in the output of the cf routes command, so a new column must be added to the output. Also, the apps mapped to the route should be displayed in the apps column and must be separated with commas. Co-authored-by: Hector Calderon --- actor/v7action/route.go | 13 +++ actor/v7action/route_test.go | 20 ++++- command/v7/routes_command.go | 2 + command/v7/routes_command_test.go | 29 +++++-- integration/helpers/version.go | 6 +- .../v7/isolated/routes_command_test.go | 85 +++++++++++++++---- 6 files changed, 126 insertions(+), 29 deletions(-) diff --git a/actor/v7action/route.go b/actor/v7action/route.go index 14bde2bf456..d59c318c61f 100644 --- a/actor/v7action/route.go +++ b/actor/v7action/route.go @@ -20,6 +20,7 @@ import ( type RouteSummary struct { resources.Route AppNames []string + AppProtocols []string DomainName string SpaceName string ServiceInstanceName string @@ -275,13 +276,25 @@ func (actor Actor) GetRouteSummaries(routes []resources.Route) ([]RouteSummary, for _, route := range routes { var appNames []string + protocolSet := map[string]bool{} for _, destination := range route.Destinations { appNames = append(appNames, appNamesByGUID[destination.App.GUID]) + protocolSet[destination.Protocol] = true + } + + var appProtocols []string + if len(protocolSet) > 0 { + appProtocols = make([]string, 0, len(protocolSet)) + for key := range protocolSet { + appProtocols = append(appProtocols, key) + } + sort.Strings(appProtocols) } routeSummaries = append(routeSummaries, RouteSummary{ Route: route, AppNames: appNames, + AppProtocols: appProtocols, SpaceName: spaceNamesByGUID[route.SpaceGUID], DomainName: getDomainName(route.URL, route.Host, route.Path, route.Port), ServiceInstanceName: serviceInstanceNameByRouteGUID[route.GUID], diff --git a/actor/v7action/route_test.go b/actor/v7action/route_test.go index 01eafeca46a..064b1863761 100644 --- a/actor/v7action/route_test.go +++ b/actor/v7action/route_test.go @@ -677,6 +677,7 @@ var _ = Describe("Route Actions", func() { App: resources.RouteDestinationApp{ GUID: "app-guid-1", }, + Protocol: "http1", }, }, SpaceGUID: "fake-space-1-guid", @@ -692,11 +693,13 @@ var _ = Describe("Route Actions", func() { App: resources.RouteDestinationApp{ GUID: "app-guid-1", }, + Protocol: "http2", }, { App: resources.RouteDestinationApp{ GUID: "app-guid-2", }, + Protocol: "http1", }, }, SpaceGUID: "fake-space-1-guid", @@ -797,7 +800,8 @@ var _ = Describe("Route Actions", func() { GUID: "route-guid-1", Destinations: []resources.RouteDestination{ { - App: resources.RouteDestinationApp{GUID: "app-guid-1"}, + App: resources.RouteDestinationApp{GUID: "app-guid-1"}, + Protocol: "http1", }, }, SpaceGUID: "fake-space-1-guid", @@ -807,6 +811,7 @@ var _ = Describe("Route Actions", func() { Port: 1, }, AppNames: []string{"app-name-1"}, + AppProtocols: []string{"http1"}, DomainName: "fake-url-1/fake-path-1", SpaceName: "fake-space-1", ServiceInstanceName: "foo", @@ -816,10 +821,12 @@ var _ = Describe("Route Actions", func() { GUID: "route-guid-2", Destinations: []resources.RouteDestination{ { - App: resources.RouteDestinationApp{GUID: "app-guid-1"}, + App: resources.RouteDestinationApp{GUID: "app-guid-1"}, + Protocol: "http2", }, { - App: resources.RouteDestinationApp{GUID: "app-guid-2"}, + App: resources.RouteDestinationApp{GUID: "app-guid-2"}, + Protocol: "http1", }, }, SpaceGUID: "fake-space-1-guid", @@ -829,6 +836,7 @@ var _ = Describe("Route Actions", func() { Port: 2, }, AppNames: []string{"app-name-1", "app-name-2"}, + AppProtocols: []string{"http1", "http2"}, DomainName: "fake-url-2/fake-path-2", SpaceName: "fake-space-1", ServiceInstanceName: "bar", @@ -928,6 +936,10 @@ var _ = Describe("Route Actions", func() { for i := 0; i < batcher.BatchSize*batches; i++ { port := i + 1000 + appProtocol := "http1" + if i%2 == 0 { + appProtocol = "http2" + } route := resources.Route{ GUID: fmt.Sprintf("route-guid-%d", i), Destinations: []resources.RouteDestination{ @@ -935,6 +947,7 @@ var _ = Describe("Route Actions", func() { App: resources.RouteDestinationApp{ GUID: fmt.Sprintf("fake-app-guid-%d", i), }, + Protocol: appProtocol, }, }, SpaceGUID: fmt.Sprintf("fake-space-guid-%d", i), @@ -968,6 +981,7 @@ var _ = Describe("Route Actions", func() { manyResults = append(manyResults, RouteSummary{ Route: route, + AppProtocols: []string{appProtocol}, AppNames: []string{fmt.Sprintf("fake-app-name-%d", i)}, DomainName: fmt.Sprintf("fake-url-%d/fake-path-%d", i, i), SpaceName: fmt.Sprintf("fake-space-name-%d", i), diff --git a/command/v7/routes_command.go b/command/v7/routes_command.go index e0c2fd8a0f4..4bbb3ac0120 100644 --- a/command/v7/routes_command.go +++ b/command/v7/routes_command.go @@ -82,6 +82,7 @@ func (cmd RoutesCommand) displayRoutesTable(routeSummaries []v7action.RouteSumma cmd.UI.TranslateText("port"), cmd.UI.TranslateText("path"), cmd.UI.TranslateText("protocol"), + cmd.UI.TranslateText("app-protocol"), cmd.UI.TranslateText("apps"), cmd.UI.TranslateText("service instance"), }, @@ -99,6 +100,7 @@ func (cmd RoutesCommand) displayRoutesTable(routeSummaries []v7action.RouteSumma port, routeSummary.Path, routeSummary.Protocol, + strings.Join(routeSummary.AppProtocols, ", "), strings.Join(routeSummary.AppNames, ", "), routeSummary.ServiceInstanceName, }) diff --git a/command/v7/routes_command_test.go b/command/v7/routes_command_test.go index 9b7699124f1..ad012886b60 100644 --- a/command/v7/routes_command_test.go +++ b/command/v7/routes_command_test.go @@ -29,7 +29,7 @@ var _ = Describe("routes Command", func() { binaryName string ) - const tableHeaders = `space\s+host\s+domain\s+port\s+path\s+protocol\s+apps\s+service instance` + const tableHeaders = `space\s+host\s+domain\s+port\s+path\s+protocol\s+app-protocol\s+apps\s+service instance` BeforeEach(func() { testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) @@ -144,10 +144,16 @@ var _ = Describe("routes Command", func() { Route: resources.Route{GUID: "route-guid-2", Host: "host-3", Path: "/path/2"}, }, { - DomainName: "domain3", - SpaceName: "space-3", - Route: resources.Route{GUID: "route-guid-3", Host: "host-1"}, + DomainName: "domain3", + SpaceName: "space-3", + Route: resources.Route{GUID: "route-guid-3", Host: "host-1", + Destinations: []resources.RouteDestination{ + {GUID: "app1-guid", Protocol: "http1"}, + {GUID: "app2-guid", Protocol: "http2"}, + }, + }, AppNames: []string{"app1", "app2"}, + AppProtocols: []string{"http1", "http2"}, ServiceInstanceName: "si-3", }, { @@ -156,6 +162,18 @@ var _ = Describe("routes Command", func() { Route: resources.Route{GUID: "route-guid-3", Port: 1024}, AppNames: []string{"app1", "app2"}, }, + { + DomainName: "domain4", + SpaceName: "space-3", + Route: resources.Route{GUID: "route-guid-3", Port: 1024, + Destinations: []resources.RouteDestination{ + {GUID: "app1-guid", Protocol: "http1"}, + {GUID: "app2-guid", Protocol: "http1"}, + }, + }, + AppNames: []string{"app1", "app2"}, + AppProtocols: []string{"http1"}, + }, } fakeActor.GetRouteSummariesReturns( @@ -174,8 +192,9 @@ var _ = Describe("routes Command", func() { Expect(testUI.Out).To(Say(tableHeaders)) Expect(testUI.Out).To(Say(`space-1\s+domain1\s+si-1\s+`)) Expect(testUI.Out).To(Say(`space-2\s+host-3\s+domain2\s+\/path\/2`)) - Expect(testUI.Out).To(Say(`space-3\s+host-1\s+domain3\s+app1, app2\s+si-3`)) + Expect(testUI.Out).To(Say(`space-3\s+host-1\s+domain3\s+http1, http2\s+app1, app2\s+si-3`)) Expect(testUI.Out).To(Say(`space-3\s+tcp\.domain\s+1024\s+app1, app2`)) + Expect(testUI.Out).To(Say(`space-3\s+domain4\s+1024\s+http1\s+app1, app2`)) }) }) diff --git a/integration/helpers/version.go b/integration/helpers/version.go index 57297bec1aa..bf9dd585711 100644 --- a/integration/helpers/version.go +++ b/integration/helpers/version.go @@ -87,11 +87,11 @@ func SkipIfUAAVersionAtLeast(version string) { } func matchMajorAPIVersion(minVersion string) string { - version := GetAPIVersionV2() if strings.HasPrefix(minVersion, "3") { - version = getAPIVersionV3() + return getAPIVersionV3() + } else { + return GetAPIVersionV2() } - return version } // GetAPIVersionV2 returns the V2 api version of the targeted API diff --git a/integration/v7/isolated/routes_command_test.go b/integration/v7/isolated/routes_command_test.go index fc2e70450c0..73813867368 100644 --- a/integration/v7/isolated/routes_command_test.go +++ b/integration/v7/isolated/routes_command_test.go @@ -1,6 +1,9 @@ package isolated import ( + "fmt" + + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" . "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers" "code.cloudfoundry.org/cli/integration/helpers" @@ -11,6 +14,9 @@ import ( ) var _ = Describe("routes command", func() { + + appProtocolValue := "http1" + const tableHeaders = `space\s+host\s+domain\s+port\s+path\s+protocol\s+app-protocol\s+apps\s+service instance` Context("Help", func() { It("appears in cf help -a", func() { session := helpers.CF("help", "-a") @@ -60,6 +66,10 @@ var _ = Describe("routes command", func() { helpers.SetupCF(orgName, spaceName) userName, _ = helpers.GetCredentials() + if !helpers.IsVersionMet(ccversion.MinVersionHTTP2RoutingV3) { + appProtocolValue = "" + } + }) AfterEach(func() { @@ -110,38 +120,77 @@ var _ = Describe("routes command", func() { It("lists all the routes", func() { session := helpers.CF("routes") Eventually(session).Should(Exit(0)) - Expect(session).To(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) - Expect(session).To(Say(`space\s+host\s+domain\s+port\s+path\s+protocol\s+apps\s+service instance\n`)) - Expect(session).To(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\n`, spaceName, domainName, appName1, serviceInstanceName)) - Expect(session).To(Say(`%s\s+route1a\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName1)) - Expect(session).To(Say(`%s\s+route1b\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName1)) - Expect(session).ToNot(Say(`%s\s+route2\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName2)) + Expect(session).To(Say(tableHeaders)) + Expect(session).To(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\s+%s\n`, spaceName, domainName, appProtocolValue, appName1, serviceInstanceName)) + Expect(session).To(Say(`%s\s+route1a\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName1)) + Expect(session).To(Say(`%s\s+route1b\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName1)) + Expect(session).ToNot(Say(`%s\s+route2\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName2)) }) It("lists all the routes by label", func() { session := helpers.CF("routes", "--labels", "env in (prod)") Eventually(session).Should(Exit(0)) Expect(session).To(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) - Expect(session).To(Say(`space\s+host\s+domain\s+port\s+path\s+protocol\s+apps\s+service instance\n`)) - Expect(session).ToNot(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\n`, spaceName, domainName, appName1, serviceInstanceName)) - Expect(session).ToNot(Say(`%s\s+route1a\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName1)) - Expect(session).To(Say(`%s\s+route1b\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName1)) - Expect(session).ToNot(Say(`%s\s+route2\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName2)) + Expect(session).To(Say(tableHeaders)) + Expect(session).ToNot(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\s+%s\n`, spaceName, domainName, appProtocolValue, appName1, serviceInstanceName)) + Expect(session).ToNot(Say(`%s\s+route1a\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName1)) + Expect(session).To(Say(`%s\s+route1b\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName1)) + Expect(session).ToNot(Say(`%s\s+route2\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName2)) }) When("fetching routes by org", func() { It("lists all the routes in the org", func() { session := helpers.CF("routes", "--org-level") - Eventually(session).Should(Say(`Getting routes for org %s as %s\.\.\.`, orgName, userName)) - Eventually(session).Should(Say(`space\s+host\s+domain\s+port\s+path\s+protocol\s+apps\s+service instance\n`)) - Eventually(session).Should(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\n`, spaceName, domainName, appName1, serviceInstanceName)) - Eventually(session).Should(Say(`%s\s+route2\s+%s\s+\/dodo\s+http\s+%s\s+\n`, otherSpaceName, domainName, appName2)) Eventually(session).Should(Exit(0)) + Expect(session).To(Say(`Getting routes for org %s as %s\.\.\.`, orgName, userName)) + Expect(session).To(Say(tableHeaders)) + Expect(session).To(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\s+%s\n`, spaceName, domainName, appProtocolValue, appName1, serviceInstanceName)) + Expect(session).To(Say(`%s\s+route2\s+%s\s+\/dodo\s+http\s+%s\s+%s\s+\n`, otherSpaceName, domainName, appProtocolValue, appName2)) }) }) }) + When("http1 and http2 routes exist", func() { + var ( + domainName string + domain helpers.Domain + ) + + BeforeEach(func() { + helpers.SkipIfVersionLessThan(ccversion.MinVersionHTTP2RoutingV3) + domainName = helpers.NewDomainName() + + domain = helpers.NewDomain(orgName, domainName) + + appName1 = helpers.NewAppName() + Eventually(helpers.CF("create-app", appName1)).Should(Exit(0)) + appName2 = helpers.NewAppName() + Eventually(helpers.CF("create-app", appName2)).Should(Exit(0)) + + domain.CreatePrivate() + + Eventually(helpers.CF("map-route", appName1, domainName, "--hostname", "route1")).Should(Exit(0)) + Eventually(helpers.CF("map-route", appName2, domainName, "--hostname", "route2")).Should(Exit(0)) + Eventually(helpers.CF("map-route", appName2, domainName, "--hostname", "route1", "--app-protocol", "http2")).Should(Exit(0)) + + helpers.SetupCF(orgName, spaceName) + }) + + AfterEach(func() { + domain.Delete() + }) + + It("lists all the routes", func() { + session := helpers.CF("routes") + Eventually(session).Should(Exit(0)) + Expect(session).To(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) + Expect(session).To(Say(tableHeaders)) + Expect(session).To(Say(`%s\s+route1\s+%s\s+http\s+http1, http2\s+%s\s+\n`, spaceName, domainName, fmt.Sprintf("%s, %s", appName1, appName2))) + Expect(session).To(Say(`%s\s+route2\s+%s\s+http\s+http1\s+%s\s+\n`, spaceName, domainName, appName2)) + }) + }) + When("when shared tcp routes exist", func() { var ( domainName string @@ -174,7 +223,7 @@ var _ = Describe("routes command", func() { Eventually(session).Should(Exit(0)) Expect(session).To(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) - Expect(session).To(Say(`space\s+host\s+domain\s+port\s+path\s+protocol\s+apps`)) + Expect(session).To(Say(tableHeaders)) Expect(session).To(Say(`%s\s+%s[^:]\s+%d\s+tcp`, spaceName, domainName, 1028)) }) }) @@ -182,9 +231,9 @@ var _ = Describe("routes command", func() { When("no routes exist", func() { It("outputs a message about no routes existing", func() { session := helpers.CF("routes") - Eventually(session).Should(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) - Eventually(session).Should(Say("No routes found")) Eventually(session).Should(Exit(0)) + Expect(session).To(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) + Expect(session).To(Say("No routes found")) }) }) }) From 685c1021992221b9ecb16f1fc69041fe0d267e82 Mon Sep 17 00:00:00 2001 From: Juan Diego Gonzalez Date: Tue, 23 Nov 2021 20:39:06 +0000 Subject: [PATCH 008/248] Revert route and routes commands HTTP/2 support(#2230) Co-authored-by: Hector Calderon --- actor/v7action/route.go | 13 --- actor/v7action/route_test.go | 20 +---- command/v7/map_route_command.go | 20 ++--- command/v7/map_route_command_test.go | 24 +++--- command/v7/route_command.go | 2 +- command/v7/route_command_test.go | 2 +- command/v7/routes_command.go | 2 - command/v7/routes_command_test.go | 29 ++----- integration/helpers/version.go | 6 +- .../v7/isolated/map_route_command_test.go | 10 +-- integration/v7/isolated/route_command_test.go | 4 +- .../v7/isolated/routes_command_test.go | 85 ++++--------------- 12 files changed, 60 insertions(+), 157 deletions(-) diff --git a/actor/v7action/route.go b/actor/v7action/route.go index d59c318c61f..14bde2bf456 100644 --- a/actor/v7action/route.go +++ b/actor/v7action/route.go @@ -20,7 +20,6 @@ import ( type RouteSummary struct { resources.Route AppNames []string - AppProtocols []string DomainName string SpaceName string ServiceInstanceName string @@ -276,25 +275,13 @@ func (actor Actor) GetRouteSummaries(routes []resources.Route) ([]RouteSummary, for _, route := range routes { var appNames []string - protocolSet := map[string]bool{} for _, destination := range route.Destinations { appNames = append(appNames, appNamesByGUID[destination.App.GUID]) - protocolSet[destination.Protocol] = true - } - - var appProtocols []string - if len(protocolSet) > 0 { - appProtocols = make([]string, 0, len(protocolSet)) - for key := range protocolSet { - appProtocols = append(appProtocols, key) - } - sort.Strings(appProtocols) } routeSummaries = append(routeSummaries, RouteSummary{ Route: route, AppNames: appNames, - AppProtocols: appProtocols, SpaceName: spaceNamesByGUID[route.SpaceGUID], DomainName: getDomainName(route.URL, route.Host, route.Path, route.Port), ServiceInstanceName: serviceInstanceNameByRouteGUID[route.GUID], diff --git a/actor/v7action/route_test.go b/actor/v7action/route_test.go index 064b1863761..01eafeca46a 100644 --- a/actor/v7action/route_test.go +++ b/actor/v7action/route_test.go @@ -677,7 +677,6 @@ var _ = Describe("Route Actions", func() { App: resources.RouteDestinationApp{ GUID: "app-guid-1", }, - Protocol: "http1", }, }, SpaceGUID: "fake-space-1-guid", @@ -693,13 +692,11 @@ var _ = Describe("Route Actions", func() { App: resources.RouteDestinationApp{ GUID: "app-guid-1", }, - Protocol: "http2", }, { App: resources.RouteDestinationApp{ GUID: "app-guid-2", }, - Protocol: "http1", }, }, SpaceGUID: "fake-space-1-guid", @@ -800,8 +797,7 @@ var _ = Describe("Route Actions", func() { GUID: "route-guid-1", Destinations: []resources.RouteDestination{ { - App: resources.RouteDestinationApp{GUID: "app-guid-1"}, - Protocol: "http1", + App: resources.RouteDestinationApp{GUID: "app-guid-1"}, }, }, SpaceGUID: "fake-space-1-guid", @@ -811,7 +807,6 @@ var _ = Describe("Route Actions", func() { Port: 1, }, AppNames: []string{"app-name-1"}, - AppProtocols: []string{"http1"}, DomainName: "fake-url-1/fake-path-1", SpaceName: "fake-space-1", ServiceInstanceName: "foo", @@ -821,12 +816,10 @@ var _ = Describe("Route Actions", func() { GUID: "route-guid-2", Destinations: []resources.RouteDestination{ { - App: resources.RouteDestinationApp{GUID: "app-guid-1"}, - Protocol: "http2", + App: resources.RouteDestinationApp{GUID: "app-guid-1"}, }, { - App: resources.RouteDestinationApp{GUID: "app-guid-2"}, - Protocol: "http1", + App: resources.RouteDestinationApp{GUID: "app-guid-2"}, }, }, SpaceGUID: "fake-space-1-guid", @@ -836,7 +829,6 @@ var _ = Describe("Route Actions", func() { Port: 2, }, AppNames: []string{"app-name-1", "app-name-2"}, - AppProtocols: []string{"http1", "http2"}, DomainName: "fake-url-2/fake-path-2", SpaceName: "fake-space-1", ServiceInstanceName: "bar", @@ -936,10 +928,6 @@ var _ = Describe("Route Actions", func() { for i := 0; i < batcher.BatchSize*batches; i++ { port := i + 1000 - appProtocol := "http1" - if i%2 == 0 { - appProtocol = "http2" - } route := resources.Route{ GUID: fmt.Sprintf("route-guid-%d", i), Destinations: []resources.RouteDestination{ @@ -947,7 +935,6 @@ var _ = Describe("Route Actions", func() { App: resources.RouteDestinationApp{ GUID: fmt.Sprintf("fake-app-guid-%d", i), }, - Protocol: appProtocol, }, }, SpaceGUID: fmt.Sprintf("fake-space-guid-%d", i), @@ -981,7 +968,6 @@ var _ = Describe("Route Actions", func() { manyResults = append(manyResults, RouteSummary{ Route: route, - AppProtocols: []string{appProtocol}, AppNames: []string{fmt.Sprintf("fake-app-name-%d", i)}, DomainName: fmt.Sprintf("fake-url-%d/fake-path-%d", i, i), SpaceName: fmt.Sprintf("fake-space-name-%d", i), diff --git a/command/v7/map_route_command.go b/command/v7/map_route_command.go index fbeba5b12ed..4224b40741c 100644 --- a/command/v7/map_route_command.go +++ b/command/v7/map_route_command.go @@ -8,11 +8,11 @@ import ( type MapRouteCommand struct { BaseCommand - RequiredArgs flag.AppDomain `positional-args:"yes"` - Hostname string `long:"hostname" short:"n" description:"Hostname for the HTTP route (required for shared domains)"` - Path flag.V7RoutePath `long:"path" description:"Path for the HTTP route"` - Port int `long:"port" description:"Port for the TCP route (default: random port)"` - AppProtocol string `long:"app-protocol" description:"[Beta flag, subject to change] Protocol for the route destination (default: http1). Only applied to HTTP routes"` + RequiredArgs flag.AppDomain `positional-args:"yes"` + Hostname string `long:"hostname" short:"n" description:"Hostname for the HTTP route (required for shared domains)"` + Path flag.V7RoutePath `long:"path" description:"Path for the HTTP route"` + Port int `long:"port" description:"Port for the TCP route (default: random port)"` + DestinationProtocol string `long:"destination-protocol" description:"[Beta flag, subject to change] Protocol for the route destination (default: http1). Only applied to HTTP routes"` relatedCommands interface{} `related_commands:"create-route, routes, unmap-route"` } @@ -20,7 +20,7 @@ type MapRouteCommand struct { func (cmd MapRouteCommand) Usage() string { return ` Map an HTTP route: - CF_NAME map-route APP_NAME DOMAIN [--hostname HOSTNAME] [--path PATH] [--app-protocol PROTOCOL] + CF_NAME map-route APP_NAME DOMAIN [--hostname HOSTNAME] [--path PATH] [--destination-protocol PROTOCOL] Map a TCP route: CF_NAME map-route APP_NAME DOMAIN [--port PORT]` @@ -31,7 +31,7 @@ func (cmd MapRouteCommand) Examples() string { CF_NAME map-route my-app example.com # example.com CF_NAME map-route my-app example.com --hostname myhost # myhost.example.com CF_NAME map-route my-app example.com --hostname myhost --path foo # myhost.example.com/foo -CF_NAME map-route my-app example.com --hostname myhost --app-protocol http2 # myhost.example.com +CF_NAME map-route my-app example.com --hostname myhost --destination-protocol http2 # myhost.example.com CF_NAME map-route my-app example.com --port 5000 # example.com:5000` } @@ -88,14 +88,14 @@ func (cmd MapRouteCommand) Execute(args []string) error { cmd.UI.DisplayOK() } - if cmd.AppProtocol != "" { + if cmd.DestinationProtocol != "" { cmd.UI.DisplayTextWithFlavor("Mapping route {{.URL}} to app {{.AppName}} with protocol {{.Protocol}} in org {{.OrgName}} / space {{.SpaceName}} as {{.User}}...", map[string]interface{}{ "URL": route.URL, "AppName": cmd.RequiredArgs.App, "User": user.Name, "SpaceName": cmd.Config.TargetedSpace().Name, "OrgName": cmd.Config.TargetedOrganization().Name, - "Protocol": cmd.AppProtocol, + "Protocol": cmd.DestinationProtocol, }) } else { @@ -121,7 +121,7 @@ func (cmd MapRouteCommand) Execute(args []string) error { cmd.UI.DisplayOK() return nil } - warnings, err = cmd.Actor.MapRoute(route.GUID, app.GUID, cmd.AppProtocol) + warnings, err = cmd.Actor.MapRoute(route.GUID, app.GUID, cmd.DestinationProtocol) cmd.UI.DisplayWarnings(warnings) if err != nil { return err diff --git a/command/v7/map_route_command_test.go b/command/v7/map_route_command_test.go index 6cef92a3f7f..00e8154a7a8 100644 --- a/command/v7/map_route_command_test.go +++ b/command/v7/map_route_command_test.go @@ -53,10 +53,10 @@ var _ = Describe("map-route Command", func() { spaceGUID = "some-space-guid" cmd = MapRouteCommand{ - RequiredArgs: flag.AppDomain{App: appName, Domain: domain}, - Hostname: hostname, - Path: flag.V7RoutePath{Path: path}, - AppProtocol: "http2", + RequiredArgs: flag.AppDomain{App: appName, Domain: domain}, + Hostname: hostname, + Path: flag.V7RoutePath{Path: path}, + DestinationProtocol: "http2", BaseCommand: BaseCommand{ UI: testUI, Config: fakeConfig, @@ -372,10 +372,10 @@ var _ = Describe("map-route Command", func() { Expect(actualPort).To(Equal(cmd.Port)) Expect(fakeActor.MapRouteCallCount()).To(Equal(1)) - actualRouteGUID, actualAppGUID, actualAppProtocol := fakeActor.MapRouteArgsForCall(0) + actualRouteGUID, actualAppGUID, actualDestinationProtocol := fakeActor.MapRouteArgsForCall(0) Expect(actualRouteGUID).To(Equal("route-guid")) Expect(actualAppGUID).To(Equal("app-guid")) - Expect(actualAppProtocol).To(Equal("http2")) + Expect(actualDestinationProtocol).To(Equal("http2")) }) }) @@ -411,10 +411,10 @@ var _ = Describe("map-route Command", func() { Expect(actualPort).To(Equal(cmd.Port)) Expect(fakeActor.MapRouteCallCount()).To(Equal(1)) - actualRouteGUID, actualAppGUID, actualAppProtocol := fakeActor.MapRouteArgsForCall(0) + actualRouteGUID, actualAppGUID, actualDestinationProtocol := fakeActor.MapRouteArgsForCall(0) Expect(actualRouteGUID).To(Equal("route-guid")) Expect(actualAppGUID).To(Equal("app-guid")) - Expect(actualAppProtocol).To(Equal("http2")) + Expect(actualDestinationProtocol).To(Equal("http2")) }) }) }) @@ -534,10 +534,10 @@ var _ = Describe("map-route Command", func() { Expect(actualPort).To(Equal(cmd.Port)) Expect(fakeActor.MapRouteCallCount()).To(Equal(1)) - actualRouteGUID, actualAppGUID, actualAppProtocol := fakeActor.MapRouteArgsForCall(0) + actualRouteGUID, actualAppGUID, actualDestinationProtocol := fakeActor.MapRouteArgsForCall(0) Expect(actualRouteGUID).To(Equal("route-guid")) Expect(actualAppGUID).To(Equal("app-guid")) - Expect(actualAppProtocol).To(Equal("http2")) + Expect(actualDestinationProtocol).To(Equal("http2")) }) }) @@ -573,10 +573,10 @@ var _ = Describe("map-route Command", func() { Expect(actualPort).To(Equal(cmd.Port)) Expect(fakeActor.MapRouteCallCount()).To(Equal(1)) - actualRouteGUID, actualAppGUID, actualAppProtocol := fakeActor.MapRouteArgsForCall(0) + actualRouteGUID, actualAppGUID, actualDestinationProtocol := fakeActor.MapRouteArgsForCall(0) Expect(actualRouteGUID).To(Equal("route-guid")) Expect(actualAppGUID).To(Equal("app-guid")) - Expect(actualAppProtocol).To(Equal("http2")) + Expect(actualDestinationProtocol).To(Equal("http2")) }) }) }) diff --git a/command/v7/route_command.go b/command/v7/route_command.go index 86dbc69ba6b..5c89398e8ff 100644 --- a/command/v7/route_command.go +++ b/command/v7/route_command.go @@ -116,7 +116,7 @@ func (cmd RouteCommand) displayDestinations(route resources.Route, appMap map[st cmd.UI.TranslateText("app"), cmd.UI.TranslateText("process"), cmd.UI.TranslateText("port"), - cmd.UI.TranslateText("app-protocol"), + cmd.UI.TranslateText("protocol"), }, } diff --git a/command/v7/route_command_test.go b/command/v7/route_command_test.go index d209c055bac..2d616beafb4 100644 --- a/command/v7/route_command_test.go +++ b/command/v7/route_command_test.go @@ -220,7 +220,7 @@ var _ = Describe("route Command", func() { Expect(testUI.Out).To(Say(`protocol:\s+http`)) Expect(testUI.Out).To(Say(`\n`)) Expect(testUI.Out).To(Say(`Destinations:`)) - Expect(testUI.Out).To(Say(`\s+app\s+process\s+port\s+app-protocol`)) + Expect(testUI.Out).To(Say(`\s+app\s+process\s+port\s+protocol`)) Expect(testUI.Out).To(Say(`\s+app-name\s+web\s+8080\s+http1`)) Expect(testUI.Out).To(Say(`\s+other-app-name\s+web\s+1337\s+http2`)) diff --git a/command/v7/routes_command.go b/command/v7/routes_command.go index 4bbb3ac0120..e0c2fd8a0f4 100644 --- a/command/v7/routes_command.go +++ b/command/v7/routes_command.go @@ -82,7 +82,6 @@ func (cmd RoutesCommand) displayRoutesTable(routeSummaries []v7action.RouteSumma cmd.UI.TranslateText("port"), cmd.UI.TranslateText("path"), cmd.UI.TranslateText("protocol"), - cmd.UI.TranslateText("app-protocol"), cmd.UI.TranslateText("apps"), cmd.UI.TranslateText("service instance"), }, @@ -100,7 +99,6 @@ func (cmd RoutesCommand) displayRoutesTable(routeSummaries []v7action.RouteSumma port, routeSummary.Path, routeSummary.Protocol, - strings.Join(routeSummary.AppProtocols, ", "), strings.Join(routeSummary.AppNames, ", "), routeSummary.ServiceInstanceName, }) diff --git a/command/v7/routes_command_test.go b/command/v7/routes_command_test.go index ad012886b60..9b7699124f1 100644 --- a/command/v7/routes_command_test.go +++ b/command/v7/routes_command_test.go @@ -29,7 +29,7 @@ var _ = Describe("routes Command", func() { binaryName string ) - const tableHeaders = `space\s+host\s+domain\s+port\s+path\s+protocol\s+app-protocol\s+apps\s+service instance` + const tableHeaders = `space\s+host\s+domain\s+port\s+path\s+protocol\s+apps\s+service instance` BeforeEach(func() { testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) @@ -144,16 +144,10 @@ var _ = Describe("routes Command", func() { Route: resources.Route{GUID: "route-guid-2", Host: "host-3", Path: "/path/2"}, }, { - DomainName: "domain3", - SpaceName: "space-3", - Route: resources.Route{GUID: "route-guid-3", Host: "host-1", - Destinations: []resources.RouteDestination{ - {GUID: "app1-guid", Protocol: "http1"}, - {GUID: "app2-guid", Protocol: "http2"}, - }, - }, + DomainName: "domain3", + SpaceName: "space-3", + Route: resources.Route{GUID: "route-guid-3", Host: "host-1"}, AppNames: []string{"app1", "app2"}, - AppProtocols: []string{"http1", "http2"}, ServiceInstanceName: "si-3", }, { @@ -162,18 +156,6 @@ var _ = Describe("routes Command", func() { Route: resources.Route{GUID: "route-guid-3", Port: 1024}, AppNames: []string{"app1", "app2"}, }, - { - DomainName: "domain4", - SpaceName: "space-3", - Route: resources.Route{GUID: "route-guid-3", Port: 1024, - Destinations: []resources.RouteDestination{ - {GUID: "app1-guid", Protocol: "http1"}, - {GUID: "app2-guid", Protocol: "http1"}, - }, - }, - AppNames: []string{"app1", "app2"}, - AppProtocols: []string{"http1"}, - }, } fakeActor.GetRouteSummariesReturns( @@ -192,9 +174,8 @@ var _ = Describe("routes Command", func() { Expect(testUI.Out).To(Say(tableHeaders)) Expect(testUI.Out).To(Say(`space-1\s+domain1\s+si-1\s+`)) Expect(testUI.Out).To(Say(`space-2\s+host-3\s+domain2\s+\/path\/2`)) - Expect(testUI.Out).To(Say(`space-3\s+host-1\s+domain3\s+http1, http2\s+app1, app2\s+si-3`)) + Expect(testUI.Out).To(Say(`space-3\s+host-1\s+domain3\s+app1, app2\s+si-3`)) Expect(testUI.Out).To(Say(`space-3\s+tcp\.domain\s+1024\s+app1, app2`)) - Expect(testUI.Out).To(Say(`space-3\s+domain4\s+1024\s+http1\s+app1, app2`)) }) }) diff --git a/integration/helpers/version.go b/integration/helpers/version.go index bf9dd585711..57297bec1aa 100644 --- a/integration/helpers/version.go +++ b/integration/helpers/version.go @@ -87,11 +87,11 @@ func SkipIfUAAVersionAtLeast(version string) { } func matchMajorAPIVersion(minVersion string) string { + version := GetAPIVersionV2() if strings.HasPrefix(minVersion, "3") { - return getAPIVersionV3() - } else { - return GetAPIVersionV2() + version = getAPIVersionV3() } + return version } // GetAPIVersionV2 returns the V2 api version of the targeted API diff --git a/integration/v7/isolated/map_route_command_test.go b/integration/v7/isolated/map_route_command_test.go index 3aaec9b04e5..ea734b65fb9 100644 --- a/integration/v7/isolated/map_route_command_test.go +++ b/integration/v7/isolated/map_route_command_test.go @@ -29,7 +29,7 @@ var _ = Describe("map-route command", func() { Eventually(session).Should(Say(`USAGE:`)) Eventually(session).Should(Say(`Map an HTTP route:\n`)) - Eventually(session).Should(Say(`cf map-route APP_NAME DOMAIN \[--hostname HOSTNAME\] \[--path PATH\] \[--app-protocol PROTOCOL\]\n`)) + Eventually(session).Should(Say(`cf map-route APP_NAME DOMAIN \[--hostname HOSTNAME\] \[--path PATH\] \[--destination-protocol PROTOCOL\]\n`)) Eventually(session).Should(Say(`Map a TCP route:\n`)) Eventually(session).Should(Say(`cf map-route APP_NAME DOMAIN \[--port PORT]\n`)) Eventually(session).Should(Say(`\n`)) @@ -38,7 +38,7 @@ var _ = Describe("map-route command", func() { Eventually(session).Should(Say(`cf map-route my-app example.com # example.com`)) Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost # myhost.example.com`)) Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost --path foo # myhost.example.com/foo`)) - Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost --app-protocol http2 # myhost.example.com`)) + Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost --destination-protocol http2 # myhost.example.com`)) Eventually(session).Should(Say(`cf map-route my-app example.com --port 5000 # example.com:5000`)) Eventually(session).Should(Say(`\n`)) @@ -46,7 +46,7 @@ var _ = Describe("map-route command", func() { Eventually(session).Should(Say(`--hostname, -n\s+Hostname for the HTTP route \(required for shared domains\)`)) Eventually(session).Should(Say(`--path\s+Path for the HTTP route`)) Eventually(session).Should(Say(`--port\s+Port for the TCP route \(default: random port\)`)) - Eventually(session).Should(Say(`--app-protocol\s+\[Beta flag, subject to change\] Protocol for the route destination \(default: http1\). Only applied to HTTP routes`)) + Eventually(session).Should(Say(`--destination-protocol\s+\[Beta flag, subject to change\] Protocol for the route destination \(default: http1\). Only applied to HTTP routes`)) Eventually(session).Should(Say(`\n`)) @@ -133,7 +133,7 @@ var _ = Describe("map-route command", func() { }) It("maps the route to an app", func() { - session := helpers.CF("map-route", appName, domainName, "--hostname", route.Host, "--app-protocol", "http2") + session := helpers.CF("map-route", appName, domainName, "--hostname", route.Host, "--destination-protocol", "http2") Eventually(session).Should(Say(`Mapping route %s.%s to app %s with protocol http2 in org %s / space %s as %s\.\.\.`, hostName, domainName, appName, orgName, spaceName, userName)) Eventually(session).Should(Say(`OK`)) @@ -227,7 +227,7 @@ var _ = Describe("map-route command", func() { }) It("maps the route to an app", func() { - session := helpers.CF("map-route", appName, domainName, "--hostname", hostName, "--app-protocol", "http2") + session := helpers.CF("map-route", appName, domainName, "--hostname", hostName, "--destination-protocol", "http2") Eventually(session).Should(Say(`Creating route %s.%s for org %s / space %s as %s\.\.\.`, hostName, domainName, orgName, spaceName, userName)) Eventually(session).Should(Say(`OK`)) Eventually(session).Should(Say(`Mapping route %s.%s to app %s with protocol http2 in org %s / space %s as %s\.\.\.`, hostName, domainName, appName, orgName, spaceName, userName)) diff --git a/integration/v7/isolated/route_command_test.go b/integration/v7/isolated/route_command_test.go index 85d50275c44..4e8d109d2fc 100644 --- a/integration/v7/isolated/route_command_test.go +++ b/integration/v7/isolated/route_command_test.go @@ -119,7 +119,7 @@ var _ = Describe("route command", func() { Eventually(session).Should(Say(`protocol:\s+http`)) Eventually(session).Should(Say(`\n`)) Eventually(session).Should(Say(`Destinations:`)) - Eventually(session).Should(Say(`\s+app\s+process\s+port\s+app-protocol`)) + Eventually(session).Should(Say(`\s+app\s+process\s+port\s+protocol`)) Eventually(session).Should(Exit(0)) }) @@ -167,7 +167,7 @@ var _ = Describe("route command", func() { Eventually(session).Should(Say(`protocol:\s+tcp`)) Eventually(session).Should(Say(`\n`)) Eventually(session).Should(Say(`Destinations:`)) - Eventually(session).Should(Say(`\s+app\s+process\s+port\s+app-protocol`)) + Eventually(session).Should(Say(`\s+app\s+process\s+port\s+protocol`)) Eventually(session).Should(Exit(0)) }) diff --git a/integration/v7/isolated/routes_command_test.go b/integration/v7/isolated/routes_command_test.go index 73813867368..fc2e70450c0 100644 --- a/integration/v7/isolated/routes_command_test.go +++ b/integration/v7/isolated/routes_command_test.go @@ -1,9 +1,6 @@ package isolated import ( - "fmt" - - "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" . "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers" "code.cloudfoundry.org/cli/integration/helpers" @@ -14,9 +11,6 @@ import ( ) var _ = Describe("routes command", func() { - - appProtocolValue := "http1" - const tableHeaders = `space\s+host\s+domain\s+port\s+path\s+protocol\s+app-protocol\s+apps\s+service instance` Context("Help", func() { It("appears in cf help -a", func() { session := helpers.CF("help", "-a") @@ -66,10 +60,6 @@ var _ = Describe("routes command", func() { helpers.SetupCF(orgName, spaceName) userName, _ = helpers.GetCredentials() - if !helpers.IsVersionMet(ccversion.MinVersionHTTP2RoutingV3) { - appProtocolValue = "" - } - }) AfterEach(func() { @@ -120,77 +110,38 @@ var _ = Describe("routes command", func() { It("lists all the routes", func() { session := helpers.CF("routes") Eventually(session).Should(Exit(0)) + Expect(session).To(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) - Expect(session).To(Say(tableHeaders)) - Expect(session).To(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\s+%s\n`, spaceName, domainName, appProtocolValue, appName1, serviceInstanceName)) - Expect(session).To(Say(`%s\s+route1a\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName1)) - Expect(session).To(Say(`%s\s+route1b\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName1)) - Expect(session).ToNot(Say(`%s\s+route2\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName2)) + Expect(session).To(Say(`space\s+host\s+domain\s+port\s+path\s+protocol\s+apps\s+service instance\n`)) + Expect(session).To(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\n`, spaceName, domainName, appName1, serviceInstanceName)) + Expect(session).To(Say(`%s\s+route1a\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName1)) + Expect(session).To(Say(`%s\s+route1b\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName1)) + Expect(session).ToNot(Say(`%s\s+route2\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName2)) }) It("lists all the routes by label", func() { session := helpers.CF("routes", "--labels", "env in (prod)") Eventually(session).Should(Exit(0)) Expect(session).To(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) - Expect(session).To(Say(tableHeaders)) - Expect(session).ToNot(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\s+%s\n`, spaceName, domainName, appProtocolValue, appName1, serviceInstanceName)) - Expect(session).ToNot(Say(`%s\s+route1a\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName1)) - Expect(session).To(Say(`%s\s+route1b\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName1)) - Expect(session).ToNot(Say(`%s\s+route2\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName2)) + Expect(session).To(Say(`space\s+host\s+domain\s+port\s+path\s+protocol\s+apps\s+service instance\n`)) + Expect(session).ToNot(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\n`, spaceName, domainName, appName1, serviceInstanceName)) + Expect(session).ToNot(Say(`%s\s+route1a\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName1)) + Expect(session).To(Say(`%s\s+route1b\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName1)) + Expect(session).ToNot(Say(`%s\s+route2\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName2)) }) When("fetching routes by org", func() { It("lists all the routes in the org", func() { session := helpers.CF("routes", "--org-level") + Eventually(session).Should(Say(`Getting routes for org %s as %s\.\.\.`, orgName, userName)) + Eventually(session).Should(Say(`space\s+host\s+domain\s+port\s+path\s+protocol\s+apps\s+service instance\n`)) + Eventually(session).Should(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\n`, spaceName, domainName, appName1, serviceInstanceName)) + Eventually(session).Should(Say(`%s\s+route2\s+%s\s+\/dodo\s+http\s+%s\s+\n`, otherSpaceName, domainName, appName2)) Eventually(session).Should(Exit(0)) - Expect(session).To(Say(`Getting routes for org %s as %s\.\.\.`, orgName, userName)) - Expect(session).To(Say(tableHeaders)) - Expect(session).To(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\s+%s\n`, spaceName, domainName, appProtocolValue, appName1, serviceInstanceName)) - Expect(session).To(Say(`%s\s+route2\s+%s\s+\/dodo\s+http\s+%s\s+%s\s+\n`, otherSpaceName, domainName, appProtocolValue, appName2)) }) }) }) - When("http1 and http2 routes exist", func() { - var ( - domainName string - domain helpers.Domain - ) - - BeforeEach(func() { - helpers.SkipIfVersionLessThan(ccversion.MinVersionHTTP2RoutingV3) - domainName = helpers.NewDomainName() - - domain = helpers.NewDomain(orgName, domainName) - - appName1 = helpers.NewAppName() - Eventually(helpers.CF("create-app", appName1)).Should(Exit(0)) - appName2 = helpers.NewAppName() - Eventually(helpers.CF("create-app", appName2)).Should(Exit(0)) - - domain.CreatePrivate() - - Eventually(helpers.CF("map-route", appName1, domainName, "--hostname", "route1")).Should(Exit(0)) - Eventually(helpers.CF("map-route", appName2, domainName, "--hostname", "route2")).Should(Exit(0)) - Eventually(helpers.CF("map-route", appName2, domainName, "--hostname", "route1", "--app-protocol", "http2")).Should(Exit(0)) - - helpers.SetupCF(orgName, spaceName) - }) - - AfterEach(func() { - domain.Delete() - }) - - It("lists all the routes", func() { - session := helpers.CF("routes") - Eventually(session).Should(Exit(0)) - Expect(session).To(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) - Expect(session).To(Say(tableHeaders)) - Expect(session).To(Say(`%s\s+route1\s+%s\s+http\s+http1, http2\s+%s\s+\n`, spaceName, domainName, fmt.Sprintf("%s, %s", appName1, appName2))) - Expect(session).To(Say(`%s\s+route2\s+%s\s+http\s+http1\s+%s\s+\n`, spaceName, domainName, appName2)) - }) - }) - When("when shared tcp routes exist", func() { var ( domainName string @@ -223,7 +174,7 @@ var _ = Describe("routes command", func() { Eventually(session).Should(Exit(0)) Expect(session).To(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) - Expect(session).To(Say(tableHeaders)) + Expect(session).To(Say(`space\s+host\s+domain\s+port\s+path\s+protocol\s+apps`)) Expect(session).To(Say(`%s\s+%s[^:]\s+%d\s+tcp`, spaceName, domainName, 1028)) }) }) @@ -231,9 +182,9 @@ var _ = Describe("routes command", func() { When("no routes exist", func() { It("outputs a message about no routes existing", func() { session := helpers.CF("routes") + Eventually(session).Should(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) + Eventually(session).Should(Say("No routes found")) Eventually(session).Should(Exit(0)) - Expect(session).To(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) - Expect(session).To(Say("No routes found")) }) }) }) From f743425609602982a270034b8bd9c79ef5793a6e Mon Sep 17 00:00:00 2001 From: Giuseppe Capizzi Date: Tue, 23 Nov 2021 22:05:35 +0100 Subject: [PATCH 009/248] Introduce CF-on-K8s support (#2233) * Detect CF-on-K8s in `cf api` * Unpin protobuf * Implement `cf login` for CF-on-K8s * Use the latest cloudfoundry/go-log-cache * Introduce a `ConnectionWrapper` for Kubernetes * Refactor the creation of the wrapped CC client * Support Kubernetes inline client certificates * Support Kubernetes client certificates of any kind * Test Kubernetes exec plugins * Support inline and filepath Kubernetes tokens * Clear the Kubernetes auth information in `cf api` * Clear the Kubernetes auth information in `cf api --unset` * Clear the Kubernetes auth information in `cf logout` * Use the real Kubernetes username when creating a space role * Use the real Kubernetes username everywhere Co-authored-by: Giuseppe Capizzi Co-authored-by: Danail Branekov Co-authored-by: Georgi Sabev Co-authored-by: Kieron Browne Co-authored-by: Mario Nitchev --- Makefile | 8 +- actor/sharedaction/actor.go | 13 +- actor/sharedaction/auth.go | 31 ++ actor/sharedaction/auth_test.go | 106 ++++ actor/sharedaction/config.go | 1 + actor/sharedaction/is_logged_in.go | 6 - actor/sharedaction/is_logged_in_test.go | 62 --- actor/sharedaction/log_cache_client.go | 2 +- actor/sharedaction/logging.go | 2 +- actor/sharedaction/logging_test.go | 2 +- .../sharedactionfakes/fake_config.go | 64 +++ .../fake_log_cache_client.go | 2 +- actor/v7action/actor.go | 17 + actor/v7action/auth.go | 40 +- actor/v7action/auth_test.go | 39 +- actor/v7action/cloud_controller_client.go | 1 + actor/v7action/config.go | 3 + actor/v7action/droplet_test.go | 4 +- actor/v7action/k8s_auth.go | 89 +++ actor/v7action/k8s_auth_test.go | 121 +++++ actor/v7action/label_test.go | 12 +- actor/v7action/logging_test.go | 2 +- actor/v7action/security_group_test.go | 1 - actor/v7action/space_test.go | 6 +- actor/v7action/stack_test.go | 1 - actor/v7action/target.go | 3 + actor/v7action/target_test.go | 30 +- actor/v7action/v7action_suite_test.go | 3 +- .../fake_cloud_controller_client.go | 74 +++ actor/v7action/v7actionfakes/fake_config.go | 171 ++++++ .../fake_kubernetes_config_getter.go | 107 ++++ .../v7action/v7actionfakes/fake_who_am_ier.go | 113 ++++ api/cloudcontroller/ccv3/info.go | 3 +- api/cloudcontroller/ccv3/info_test.go | 27 +- .../ccv3/internal/api_routes.go | 2 + api/cloudcontroller/ccv3/user.go | 11 + api/cloudcontroller/ccv3/user_test.go | 78 ++- .../wrapper/kubernetes_authentication.go | 151 ++++++ .../wrapper/kubernetes_authentication_test.go | 460 ++++++++++++++++ .../wrapper/uaa_authentication.go | 4 - .../wrapper/uaa_authentication_test.go | 16 - .../wrapper/wrapper_suite_test.go | 14 +- cf/configuration/coreconfig/config_data.go | 2 + command/commandfakes/fake_config.go | 501 +++++++++-------- command/commandfakes/fake_shared_actor.go | 42 +- command/config.go | 2 + .../not_supported_on_k8s_error.go | 19 + command/v7/actor.go | 2 + command/v7/add_network_policy_command.go | 2 +- command/v7/add_network_policy_command_test.go | 2 +- command/v7/allow_space_ssh_command.go | 6 +- command/v7/allow_space_ssh_command_test.go | 5 +- command/v7/api_command.go | 2 +- command/v7/api_command_test.go | 4 +- command/v7/app_command.go | 2 +- command/v7/app_command_test.go | 4 +- command/v7/apply_manifest_command.go | 2 +- command/v7/apply_manifest_command_test.go | 4 +- command/v7/apps_command.go | 2 +- command/v7/apps_command_test.go | 4 +- command/v7/bind_route_service_command.go | 2 +- command/v7/bind_route_service_command_test.go | 4 +- .../v7/bind_running_security_group_command.go | 2 +- ...ind_running_security_group_command_test.go | 4 +- command/v7/bind_security_group_command.go | 2 +- .../v7/bind_security_group_command_test.go | 4 +- command/v7/bind_service_command.go | 2 +- command/v7/bind_service_command_test.go | 4 +- .../v7/bind_staging_security_group_command.go | 2 +- ...ind_staging_security_group_command_test.go | 4 +- command/v7/buildpacks_command.go | 2 +- command/v7/buildpacks_command_test.go | 2 +- command/v7/cancel_deployment_command.go | 4 +- command/v7/cancel_deployment_command_test.go | 4 +- command/v7/check_route_command.go | 2 +- command/v7/check_route_command_test.go | 6 +- command/v7/copy_source_command.go | 2 +- command/v7/copy_source_command_test.go | 6 +- command/v7/create_app_command.go | 2 +- command/v7/create_app_command_test.go | 2 +- command/v7/create_app_manifest_command.go | 2 +- .../v7/create_app_manifest_command_test.go | 2 +- command/v7/create_buildpack_command.go | 2 +- command/v7/create_buildpack_command_test.go | 2 +- .../v7/create_isolation_segment_command.go | 2 +- .../create_isolation_segment_command_test.go | 2 +- command/v7/create_org_command.go | 2 +- command/v7/create_org_command_test.go | 2 +- command/v7/create_org_quota_command.go | 2 +- command/v7/create_org_quota_command_test.go | 2 +- command/v7/create_package_command.go | 6 +- command/v7/create_package_command_test.go | 2 +- command/v7/create_private_domain_command.go | 2 +- .../v7/create_private_domain_command_test.go | 2 +- command/v7/create_route_command.go | 2 +- command/v7/create_route_command_test.go | 2 +- command/v7/create_security_group_command.go | 2 +- .../v7/create_security_group_command_test.go | 2 +- command/v7/create_service_broker_command.go | 2 +- .../v7/create_service_broker_command_test.go | 4 +- command/v7/create_service_command.go | 2 +- command/v7/create_service_command_test.go | 4 +- command/v7/create_service_key_command.go | 2 +- command/v7/create_service_key_command_test.go | 4 +- command/v7/create_shared_domain_command.go | 2 +- .../v7/create_shared_domain_command_test.go | 2 +- command/v7/create_space_command.go | 6 +- command/v7/create_space_command_test.go | 2 +- command/v7/create_space_quota_command.go | 2 +- command/v7/create_space_quota_command_test.go | 2 +- .../create_user_provided_service_command.go | 2 +- ...eate_user_provided_service_command_test.go | 4 +- command/v7/delete_command.go | 2 +- command/v7/delete_command_test.go | 4 +- .../v7/delete_isolation_segment_command.go | 2 +- .../delete_isolation_segment_command_test.go | 2 +- command/v7/delete_org_command.go | 2 +- command/v7/delete_org_command_test.go | 4 +- command/v7/delete_org_quota_command.go | 2 +- command/v7/delete_org_quota_command_test.go | 2 +- command/v7/delete_orphaned_routes_command.go | 4 +- .../v7/delete_orphaned_routes_command_test.go | 5 +- command/v7/delete_private_domain_command.go | 2 +- .../v7/delete_private_domain_command_test.go | 4 +- command/v7/delete_route_command.go | 2 +- command/v7/delete_route_command_test.go | 4 +- command/v7/delete_security_group_command.go | 2 +- .../v7/delete_security_group_command_test.go | 4 +- .../v7/delete_service_broker_command_test.go | 2 +- command/v7/delete_service_command.go | 2 +- command/v7/delete_service_command_test.go | 4 +- command/v7/delete_service_key_command.go | 2 +- command/v7/delete_service_key_command_test.go | 4 +- command/v7/delete_shared_domain_command.go | 2 +- .../v7/delete_shared_domain_command_test.go | 4 +- command/v7/delete_space_command.go | 2 +- command/v7/delete_space_command_test.go | 4 +- command/v7/delete_space_quota_command.go | 2 +- command/v7/delete_space_quota_command_test.go | 2 +- command/v7/delete_user_command.go | 5 +- command/v7/delete_user_command_test.go | 8 +- command/v7/disable_feature_flag_command.go | 2 +- .../v7/disable_feature_flag_command_test.go | 2 +- command/v7/disable_org_isolation_command.go | 2 +- .../v7/disable_org_isolation_command_test.go | 4 +- command/v7/disable_service_access_command.go | 2 +- .../v7/disable_service_access_command_test.go | 2 +- command/v7/disable_ssh_command.go | 4 +- command/v7/disable_ssh_command_test.go | 4 +- command/v7/disallow_space_ssh_command.go | 6 +- command/v7/disallow_space_ssh_command_test.go | 5 +- command/v7/domains_command.go | 2 +- command/v7/domains_command_test.go | 2 +- command/v7/download_droplet_command.go | 2 +- command/v7/download_droplet_command_test.go | 2 +- command/v7/droplets_command.go | 2 +- command/v7/droplets_command_test.go | 4 +- command/v7/enable_feature_flag_command.go | 2 +- .../v7/enable_feature_flag_command_test.go | 2 +- command/v7/enable_org_isolation_command.go | 2 +- .../v7/enable_org_isolation_command_test.go | 2 +- command/v7/enable_service_access_command.go | 2 +- .../v7/enable_service_access_command_test.go | 2 +- command/v7/enable_ssh_command.go | 4 +- command/v7/enable_ssh_command_test.go | 4 +- command/v7/env_command.go | 2 +- command/v7/env_command_test.go | 4 +- command/v7/events_command.go | 2 +- command/v7/events_command_test.go | 4 +- command/v7/feature_flag_command.go | 2 +- command/v7/feature_flag_command_test.go | 2 +- command/v7/feature_flags_command.go | 2 +- command/v7/feature_flags_command_test.go | 2 +- command/v7/get_health_check_command.go | 2 +- command/v7/get_health_check_command_test.go | 4 +- command/v7/isolation_segments_command.go | 2 +- command/v7/isolation_segments_command_test.go | 2 +- command/v7/label_updater.go | 7 +- command/v7/label_updater_test.go | 65 +-- command/v7/labels_command.go | 4 +- command/v7/labels_command_test.go | 34 +- command/v7/login_command.go | 49 +- command/v7/login_command_test.go | 107 +++- command/v7/logout_command.go | 2 +- command/v7/logout_command_test.go | 6 +- command/v7/logs_command.go | 2 +- command/v7/logs_command_test.go | 2 +- command/v7/map_route_command.go | 2 +- command/v7/map_route_command_test.go | 4 +- command/v7/marketplace_command.go | 2 +- command/v7/marketplace_command_test.go | 8 +- command/v7/network_policies_command.go | 2 +- command/v7/network_policies_command_test.go | 41 +- command/v7/org_command.go | 2 +- command/v7/org_command_test.go | 6 +- command/v7/org_quota_command.go | 2 +- command/v7/org_quota_command_test.go | 4 +- command/v7/org_quotas_command.go | 2 +- command/v7/org_quotas_command_test.go | 4 +- command/v7/org_users_command.go | 2 +- command/v7/org_users_command_test.go | 4 +- command/v7/orgs_command.go | 2 +- command/v7/orgs_command_test.go | 4 +- command/v7/packages_command.go | 2 +- command/v7/packages_command_test.go | 4 +- command/v7/passwd_command.go | 2 +- command/v7/passwd_command_test.go | 4 +- command/v7/purge_service_instance_command.go | 2 +- .../v7/purge_service_instance_command_test.go | 4 +- command/v7/push_command.go | 2 +- command/v7/push_command_test.go | 10 +- command/v7/remove_network_policy_command.go | 2 +- .../v7/remove_network_policy_command_test.go | 2 +- command/v7/rename_command.go | 2 +- command/v7/rename_command_test.go | 4 +- command/v7/rename_org_command.go | 2 +- command/v7/rename_org_command_test.go | 6 +- command/v7/rename_service_broker_command.go | 2 +- .../v7/rename_service_broker_command_test.go | 4 +- command/v7/rename_service_command.go | 2 +- command/v7/rename_service_command_test.go | 4 +- command/v7/rename_space_command.go | 2 +- command/v7/rename_space_command_test.go | 6 +- ...t_org_default_isolation_segment_command.go | 2 +- ..._default_isolation_segment_command_test.go | 6 +- .../reset_space_isolation_segment_command.go | 2 +- ...et_space_isolation_segment_command_test.go | 2 +- command/v7/restage_command.go | 2 +- command/v7/restage_command_test.go | 4 +- command/v7/restart_app_instance_command.go | 2 +- .../v7/restart_app_instance_command_test.go | 4 +- command/v7/restart_command.go | 2 +- command/v7/restart_command_test.go | 4 +- command/v7/revisions_command.go | 2 +- command/v7/revisions_command_test.go | 4 +- command/v7/rollback_command.go | 2 +- command/v7/rollback_command_test.go | 4 +- command/v7/route_command.go | 2 +- command/v7/route_command_test.go | 6 +- command/v7/router_groups_command.go | 2 +- command/v7/router_groups_command_test.go | 2 +- command/v7/routes_command.go | 2 +- command/v7/routes_command_test.go | 2 +- command/v7/run_task_command.go | 2 +- command/v7/run_task_command_test.go | 4 +- ...ning_environment_variable_group_command.go | 2 +- ...environment_variable_group_command_test.go | 2 +- command/v7/running_security_groups_command.go | 2 +- .../running_security_groups_command_test.go | 4 +- command/v7/scale_command.go | 2 +- command/v7/scale_command_test.go | 4 +- command/v7/security_group_command.go | 2 +- command/v7/security_group_command_test.go | 4 +- command/v7/security_groups_command.go | 2 +- command/v7/security_groups_command_test.go | 4 +- command/v7/service_access_command.go | 2 +- command/v7/service_access_command_test.go | 6 +- command/v7/service_brokers_command.go | 2 +- command/v7/service_brokers_command_test.go | 4 +- command/v7/service_command.go | 2 +- command/v7/service_command_test.go | 2 +- command/v7/service_key_command.go | 2 +- command/v7/service_key_command_test.go | 4 +- command/v7/service_keys_command.go | 2 +- command/v7/service_keys_command_test.go | 4 +- command/v7/services_command.go | 2 +- command/v7/services_command_test.go | 4 +- command/v7/set_droplet_command.go | 2 +- command/v7/set_droplet_command_test.go | 6 +- command/v7/set_env_command.go | 2 +- command/v7/set_env_command_test.go | 4 +- command/v7/set_health_check_command.go | 2 +- command/v7/set_health_check_command_test.go | 4 +- ...t_org_default_isolation_segment_command.go | 2 +- ..._default_isolation_segment_command_test.go | 4 +- command/v7/set_org_quota_command.go | 4 +- command/v7/set_org_quota_command_test.go | 5 +- command/v7/set_org_role_command.go | 2 +- command/v7/set_org_role_command_test.go | 2 +- ...ning_environment_variable_group_command.go | 2 +- ...environment_variable_group_command_test.go | 2 +- .../v7/set_space_isolation_segment_command.go | 2 +- ...et_space_isolation_segment_command_test.go | 2 +- command/v7/set_space_quota_command.go | 4 +- command/v7/set_space_quota_command_test.go | 2 +- command/v7/set_space_role_command.go | 2 +- command/v7/set_space_role_command_test.go | 2 +- ...ging_environment_variable_group_command.go | 2 +- ...environment_variable_group_command_test.go | 2 +- command/v7/share_private_domain_command.go | 2 +- .../v7/share_private_domain_command_test.go | 4 +- command/v7/share_service_command.go | 2 +- command/v7/share_service_command_test.go | 4 +- command/v7/shared/app_stager.go | 3 +- command/v7/shared/app_stager_test.go | 8 +- command/v7/shared/new_clients.go | 41 +- command/v7/shared/new_clients_test.go | 5 +- command/v7/shared/package_displayer.go | 8 +- command/v7/space_command.go | 2 +- command/v7/space_command_test.go | 4 +- command/v7/space_quota_command.go | 2 +- command/v7/space_quota_command_test.go | 4 +- command/v7/space_quotas_command.go | 2 +- command/v7/space_quotas_command_test.go | 4 +- command/v7/space_users_command.go | 2 +- command/v7/space_users_command_test.go | 4 +- command/v7/spaces_command.go | 2 +- command/v7/spaces_command_test.go | 4 +- command/v7/ssh_enabled_command_test.go | 3 +- command/v7/stack_command.go | 2 +- command/v7/stack_command_test.go | 4 +- command/v7/stacks_command.go | 2 +- command/v7/stacks_command_test.go | 2 +- command/v7/stage_package_command.go | 2 +- command/v7/stage_package_command_test.go | 2 +- ...ging_environment_variable_group_command.go | 2 +- ...environment_variable_group_command_test.go | 2 +- command/v7/staging_security_groups_command.go | 2 +- .../staging_security_groups_command_test.go | 4 +- command/v7/start_command.go | 2 +- command/v7/start_command_test.go | 4 +- command/v7/stop_command.go | 2 +- command/v7/stop_command_test.go | 14 +- command/v7/target_command.go | 2 +- command/v7/target_command_test.go | 4 +- command/v7/tasks_command.go | 2 +- command/v7/tasks_command_test.go | 4 +- command/v7/terminate_task_command.go | 2 +- command/v7/terminate_task_command_test.go | 4 +- command/v7/unbind_route_service_command.go | 2 +- .../v7/unbind_route_service_command_test.go | 4 +- .../v7/unbind_running_group_command_test.go | 2 +- .../unbind_running_security_group_command.go | 2 +- command/v7/unbind_security_group.go | 2 +- command/v7/unbind_security_group_test.go | 4 +- command/v7/unbind_service_command.go | 2 +- command/v7/unbind_service_command_test.go | 4 +- .../unbind_staging_security_group_command.go | 2 +- ...ind_staging_security_group_command_test.go | 2 +- command/v7/unmap_route_command.go | 2 +- command/v7/unmap_route_command_test.go | 4 +- command/v7/unset_env_command.go | 2 +- command/v7/unset_env_command_test.go | 4 +- command/v7/unset_org_role_command.go | 2 +- command/v7/unset_org_role_command_test.go | 2 +- command/v7/unset_space_quota_command.go | 4 +- command/v7/unset_space_quota_command_test.go | 8 +- command/v7/unset_space_role_command.go | 2 +- command/v7/unset_space_role_command_test.go | 2 +- command/v7/unshare_private_domain_command.go | 2 +- .../v7/unshare_private_domain_command_test.go | 4 +- command/v7/unshare_service_command.go | 2 +- command/v7/unshare_service_command_test.go | 6 +- command/v7/update_buildpack_command.go | 2 +- command/v7/update_buildpack_command_test.go | 4 +- command/v7/update_org_quota_command.go | 2 +- command/v7/update_org_quota_command_test.go | 2 +- command/v7/update_security_group_command.go | 2 +- .../v7/update_security_group_command_test.go | 2 +- command/v7/update_service_broker_command.go | 2 +- .../v7/update_service_broker_command_test.go | 4 +- command/v7/update_service_command.go | 2 +- command/v7/update_service_command_test.go | 4 +- command/v7/update_space_quota_command.go | 2 +- command/v7/update_space_quota_command_test.go | 2 +- .../update_user_provided_service_command.go | 2 +- ...date_user_provided_service_command_test.go | 2 +- command/v7/upgrade_service_command.go | 2 +- command/v7/upgrade_service_command_test.go | 2 +- command/v7/v7fakes/fake_actor.go | 70 +++ command/v7/v7fakes/fake_set_label_actor.go | 70 +++ go.mod | 23 +- go.sum | 512 ++++++++++++++++-- integration/README.md | 3 +- integration/helpers/command.go | 6 +- integration/v7/isolated/api_command_test.go | 2 +- integration/v7/isolated/login_command_test.go | 2 +- .../v7/selfcontained/api_command_test.go | 99 ++++ .../create_space_command_test.go | 107 ++++ integration/v7/selfcontained/fake/cf_api.go | 68 +++ .../v7/selfcontained/kubernetes_auth_test.go | 106 ++++ .../v7/selfcontained/login_command_test.go | 165 ++++++ .../v7/selfcontained/logout_command_test.go | 29 + .../selfcontained/selfcontained_suite_test.go | 113 ++++ resources/user_resource.go | 5 + util/configv3/config.go | 13 + util/configv3/config_test.go | 23 +- .../configv3fakes/fake_user_config.go | 175 ++++++ util/configv3/default_user_config.go | 58 ++ util/configv3/default_user_config_test.go | 98 ++++ util/configv3/dynamic_user_config.go | 22 + util/configv3/dynamic_user_config_test.go | 137 +++++ util/configv3/json_config.go | 56 +- util/configv3/json_config_test.go | 133 ++--- util/configv3/k8s.go | 10 + util/configv3/k8s_test.go | 34 ++ util/configv3/kubernetes_user_config.go | 17 + util/configv3/kubernetes_user_config_test.go | 50 ++ util/configv3/load_config.go | 6 + 399 files changed, 4762 insertions(+), 1198 deletions(-) create mode 100644 actor/sharedaction/auth.go create mode 100644 actor/sharedaction/auth_test.go delete mode 100644 actor/sharedaction/is_logged_in.go delete mode 100644 actor/sharedaction/is_logged_in_test.go create mode 100644 actor/v7action/k8s_auth.go create mode 100644 actor/v7action/k8s_auth_test.go create mode 100644 actor/v7action/v7actionfakes/fake_kubernetes_config_getter.go create mode 100644 actor/v7action/v7actionfakes/fake_who_am_ier.go create mode 100644 api/cloudcontroller/wrapper/kubernetes_authentication.go create mode 100644 api/cloudcontroller/wrapper/kubernetes_authentication_test.go create mode 100644 command/translatableerror/not_supported_on_k8s_error.go create mode 100644 integration/v7/selfcontained/api_command_test.go create mode 100644 integration/v7/selfcontained/create_space_command_test.go create mode 100644 integration/v7/selfcontained/fake/cf_api.go create mode 100644 integration/v7/selfcontained/kubernetes_auth_test.go create mode 100644 integration/v7/selfcontained/login_command_test.go create mode 100644 integration/v7/selfcontained/logout_command_test.go create mode 100644 integration/v7/selfcontained/selfcontained_suite_test.go create mode 100644 util/configv3/configv3fakes/fake_user_config.go create mode 100644 util/configv3/default_user_config.go create mode 100644 util/configv3/default_user_config_test.go create mode 100644 util/configv3/dynamic_user_config.go create mode 100644 util/configv3/dynamic_user_config_test.go create mode 100644 util/configv3/k8s.go create mode 100644 util/configv3/k8s_test.go create mode 100644 util/configv3/kubernetes_user_config.go create mode 100644 util/configv3/kubernetes_user_config_test.go diff --git a/Makefile b/Makefile index dbb1521fe6c..195d9286aa3 100644 --- a/Makefile +++ b/Makefile @@ -130,11 +130,15 @@ ip: integration-push integration-push: build integration-cleanup ## Run all push-related integration tests $(ginkgo_int) -nodes $(NODES) integration/$(TARGET)/push -integration-tests: build integration-cleanup integration-isolated integration-push integration-global ## Run all isolated, push, and global integration tests +integration-selfcontained: build + $(ginkgo_int) -nodes $(NODES) integration/v7/selfcontained + +integration-tests: build integration-cleanup integration-isolated integration-push integration-global integration-selfcontained ## Run all isolated, push, selfcontained, and global integration tests + i: integration-tests-full integration-full-tests: integration-tests-full -integration-tests-full: build integration-cleanup integration-isolated integration-push integration-experimental integration-plugin integration-global ## Run all isolated, push, experimental, plugin, and global integration tests +integration-tests-full: build integration-cleanup integration-isolated integration-push integration-experimental integration-plugin integration-global integration-selfcontained ## Run all isolated, push, experimental, plugin, selfcontained, and global integration tests integration-tests-full-ci: integration-cleanup $(ginkgo_int) -nodes $(NODES) -flakeAttempts $(FLAKE_ATTEMPTS) \ diff --git a/actor/sharedaction/actor.go b/actor/sharedaction/actor.go index ade8cc2a817..11f7c31012b 100644 --- a/actor/sharedaction/actor.go +++ b/actor/sharedaction/actor.go @@ -2,14 +2,25 @@ // controller package sharedaction +type AuthActor interface { + IsLoggedIn() bool +} + // Actor handles all shared actions type Actor struct { Config Config + AuthActor } // NewActor returns an Actor with default settings func NewActor(config Config) *Actor { + var authActor AuthActor = NewDefaultAuthActor(config) + if config.IsCFOnK8s() { + authActor = NewK8sAuthActor(config) + } + return &Actor{ - Config: config, + AuthActor: authActor, + Config: config, } } diff --git a/actor/sharedaction/auth.go b/actor/sharedaction/auth.go new file mode 100644 index 00000000000..f7f5910d10a --- /dev/null +++ b/actor/sharedaction/auth.go @@ -0,0 +1,31 @@ +package sharedaction + +type DefaultAuthActor struct { + config Config +} + +func NewDefaultAuthActor(config Config) DefaultAuthActor { + return DefaultAuthActor{ + config: config, + } +} + +func (a DefaultAuthActor) IsLoggedIn() bool { + return a.config.AccessToken() != "" || a.config.RefreshToken() != "" +} + +type K8sAuthActor struct { + config Config +} + +func NewK8sAuthActor(config Config) K8sAuthActor { + return K8sAuthActor{ + config: config, + } +} + +func (a K8sAuthActor) IsLoggedIn() bool { + name, err := a.config.CurrentUserName() + + return err == nil && name != "" +} diff --git a/actor/sharedaction/auth_test.go b/actor/sharedaction/auth_test.go new file mode 100644 index 00000000000..9fbf5e65066 --- /dev/null +++ b/actor/sharedaction/auth_test.go @@ -0,0 +1,106 @@ +package sharedaction_test + +import ( + "errors" + + . "code.cloudfoundry.org/cli/actor/sharedaction" + "code.cloudfoundry.org/cli/actor/sharedaction/sharedactionfakes" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("AuthActor", func() { + var ( + actor *Actor + fakeConfig *sharedactionfakes.FakeConfig + ) + + BeforeEach(func() { + fakeConfig = new(sharedactionfakes.FakeConfig) + }) + + Context("Default CF on VMs", func() { + BeforeEach(func() { + actor = NewActor(fakeConfig) + }) + + When("only the access token is set", func() { + BeforeEach(func() { + fakeConfig.AccessTokenReturns("some-access-token") + }) + + It("returns true", func() { + Expect(actor.IsLoggedIn()).To(BeTrue()) + }) + }) + + When("only the refresh token is set", func() { + BeforeEach(func() { + fakeConfig.RefreshTokenReturns("some-refresh-token") + }) + + It("returns true", func() { + Expect(actor.IsLoggedIn()).To(BeTrue()) + }) + }) + + When("both access and refresh token are set", func() { + BeforeEach(func() { + fakeConfig.AccessTokenReturns("some-access-token") + fakeConfig.RefreshTokenReturns("some-refresh-token") + }) + + It("returns true", func() { + Expect(actor.IsLoggedIn()).To(BeTrue()) + }) + }) + + When("neither access nor refresh token are set", func() { + BeforeEach(func() { + fakeConfig.AccessTokenReturns("") + fakeConfig.RefreshTokenReturns("") + }) + + It("returns false", func() { + Expect(actor.IsLoggedIn()).To(BeFalse()) + }) + }) + }) + + Context("CF on K8s", func() { + BeforeEach(func() { + fakeConfig.IsCFOnK8sReturns(true) + actor = NewActor(fakeConfig) + }) + + When("the auth info is set", func() { + BeforeEach(func() { + fakeConfig.CurrentUserNameReturns("non-empty", nil) + }) + + It("returns true", func() { + Expect(actor.IsLoggedIn()).To(BeTrue()) + }) + }) + + When("the auth info is not set", func() { + BeforeEach(func() { + fakeConfig.CurrentUserNameReturns("", nil) + }) + + It("returns false", func() { + Expect(actor.IsLoggedIn()).To(BeFalse()) + }) + }) + + When("getting the current user name fails", func() { + BeforeEach(func() { + fakeConfig.CurrentUserNameReturns("", errors.New("boom!")) + }) + + It("returns false", func() { + Expect(actor.IsLoggedIn()).To(BeFalse()) + }) + }) + }) +}) diff --git a/actor/sharedaction/config.go b/actor/sharedaction/config.go index 217ed5054d6..32be6d2e2aa 100644 --- a/actor/sharedaction/config.go +++ b/actor/sharedaction/config.go @@ -9,6 +9,7 @@ type Config interface { CurrentUserName() (string, error) HasTargetedOrganization() bool HasTargetedSpace() bool + IsCFOnK8s() bool RefreshToken() string TargetedOrganizationName() string Verbose() (bool, []string) diff --git a/actor/sharedaction/is_logged_in.go b/actor/sharedaction/is_logged_in.go deleted file mode 100644 index e35b6736704..00000000000 --- a/actor/sharedaction/is_logged_in.go +++ /dev/null @@ -1,6 +0,0 @@ -package sharedaction - -// IsLoggedIn checks whether a user has authenticated with CF -func (actor Actor) IsLoggedIn() bool { - return actor.Config.AccessToken() != "" || actor.Config.RefreshToken() != "" -} diff --git a/actor/sharedaction/is_logged_in_test.go b/actor/sharedaction/is_logged_in_test.go deleted file mode 100644 index e81803937b5..00000000000 --- a/actor/sharedaction/is_logged_in_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package sharedaction_test - -import ( - . "code.cloudfoundry.org/cli/actor/sharedaction" - "code.cloudfoundry.org/cli/actor/sharedaction/sharedactionfakes" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("IsLoggedIn", func() { - var ( - actor *Actor - fakeConfig *sharedactionfakes.FakeConfig - ) - - BeforeEach(func() { - fakeConfig = new(sharedactionfakes.FakeConfig) - actor = NewActor(fakeConfig) - }) - - When("only the access token is set", func() { - BeforeEach(func() { - fakeConfig.AccessTokenReturns("some-access-token") - }) - - It("returns true", func() { - Expect(actor.IsLoggedIn()).To(BeTrue()) - }) - }) - - When("only the refresh token is set", func() { - BeforeEach(func() { - fakeConfig.RefreshTokenReturns("some-refresh-token") - }) - - It("returns true", func() { - Expect(actor.IsLoggedIn()).To(BeTrue()) - }) - }) - - When("both access and refresh token are set", func() { - BeforeEach(func() { - fakeConfig.AccessTokenReturns("some-access-token") - fakeConfig.RefreshTokenReturns("some-refresh-token") - }) - - It("returns true", func() { - Expect(actor.IsLoggedIn()).To(BeTrue()) - }) - }) - - When("neither access nor refresh token are set", func() { - BeforeEach(func() { - fakeConfig.AccessTokenReturns("") - fakeConfig.RefreshTokenReturns("") - }) - - It("returns false", func() { - Expect(actor.IsLoggedIn()).To(BeFalse()) - }) - }) -}) diff --git a/actor/sharedaction/log_cache_client.go b/actor/sharedaction/log_cache_client.go index b6658451f5a..ed3403a1051 100644 --- a/actor/sharedaction/log_cache_client.go +++ b/actor/sharedaction/log_cache_client.go @@ -5,7 +5,7 @@ import ( "time" logcache "code.cloudfoundry.org/go-log-cache" - "code.cloudfoundry.org/go-loggregator/rpc/loggregator_v2" + "code.cloudfoundry.org/go-loggregator/v8/rpc/loggregator_v2" ) //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . LogCacheClient diff --git a/actor/sharedaction/logging.go b/actor/sharedaction/logging.go index a7e9f419da9..820767661ac 100644 --- a/actor/sharedaction/logging.go +++ b/actor/sharedaction/logging.go @@ -10,7 +10,7 @@ import ( logcache "code.cloudfoundry.org/go-log-cache" "code.cloudfoundry.org/go-log-cache/rpc/logcache_v1" - "code.cloudfoundry.org/go-loggregator/rpc/loggregator_v2" + "code.cloudfoundry.org/go-loggregator/v8/rpc/loggregator_v2" "github.com/sirupsen/logrus" ) diff --git a/actor/sharedaction/logging_test.go b/actor/sharedaction/logging_test.go index 3263a2aec78..abbb94c1257 100644 --- a/actor/sharedaction/logging_test.go +++ b/actor/sharedaction/logging_test.go @@ -10,7 +10,7 @@ import ( "code.cloudfoundry.org/cli/actor/sharedaction" "code.cloudfoundry.org/cli/actor/sharedaction/sharedactionfakes" logcache "code.cloudfoundry.org/go-log-cache" - "code.cloudfoundry.org/go-loggregator/rpc/loggregator_v2" + "code.cloudfoundry.org/go-loggregator/v8/rpc/loggregator_v2" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) diff --git a/actor/sharedaction/sharedactionfakes/fake_config.go b/actor/sharedaction/sharedactionfakes/fake_config.go index a374545c5d1..9bad4b6fb7d 100644 --- a/actor/sharedaction/sharedactionfakes/fake_config.go +++ b/actor/sharedaction/sharedactionfakes/fake_config.go @@ -60,6 +60,16 @@ type FakeConfig struct { hasTargetedSpaceReturnsOnCall map[int]struct { result1 bool } + IsCFOnK8sStub func() bool + isCFOnK8sMutex sync.RWMutex + isCFOnK8sArgsForCall []struct { + } + isCFOnK8sReturns struct { + result1 bool + } + isCFOnK8sReturnsOnCall map[int]struct { + result1 bool + } RefreshTokenStub func() string refreshTokenMutex sync.RWMutex refreshTokenArgsForCall []struct { @@ -359,6 +369,58 @@ func (fake *FakeConfig) HasTargetedSpaceReturnsOnCall(i int, result1 bool) { }{result1} } +func (fake *FakeConfig) IsCFOnK8s() bool { + fake.isCFOnK8sMutex.Lock() + ret, specificReturn := fake.isCFOnK8sReturnsOnCall[len(fake.isCFOnK8sArgsForCall)] + fake.isCFOnK8sArgsForCall = append(fake.isCFOnK8sArgsForCall, struct { + }{}) + fake.recordInvocation("IsCFOnK8s", []interface{}{}) + fake.isCFOnK8sMutex.Unlock() + if fake.IsCFOnK8sStub != nil { + return fake.IsCFOnK8sStub() + } + if specificReturn { + return ret.result1 + } + fakeReturns := fake.isCFOnK8sReturns + return fakeReturns.result1 +} + +func (fake *FakeConfig) IsCFOnK8sCallCount() int { + fake.isCFOnK8sMutex.RLock() + defer fake.isCFOnK8sMutex.RUnlock() + return len(fake.isCFOnK8sArgsForCall) +} + +func (fake *FakeConfig) IsCFOnK8sCalls(stub func() bool) { + fake.isCFOnK8sMutex.Lock() + defer fake.isCFOnK8sMutex.Unlock() + fake.IsCFOnK8sStub = stub +} + +func (fake *FakeConfig) IsCFOnK8sReturns(result1 bool) { + fake.isCFOnK8sMutex.Lock() + defer fake.isCFOnK8sMutex.Unlock() + fake.IsCFOnK8sStub = nil + fake.isCFOnK8sReturns = struct { + result1 bool + }{result1} +} + +func (fake *FakeConfig) IsCFOnK8sReturnsOnCall(i int, result1 bool) { + fake.isCFOnK8sMutex.Lock() + defer fake.isCFOnK8sMutex.Unlock() + fake.IsCFOnK8sStub = nil + if fake.isCFOnK8sReturnsOnCall == nil { + fake.isCFOnK8sReturnsOnCall = make(map[int]struct { + result1 bool + }) + } + fake.isCFOnK8sReturnsOnCall[i] = struct { + result1 bool + }{result1} +} + func (fake *FakeConfig) RefreshToken() string { fake.refreshTokenMutex.Lock() ret, specificReturn := fake.refreshTokenReturnsOnCall[len(fake.refreshTokenArgsForCall)] @@ -531,6 +593,8 @@ func (fake *FakeConfig) Invocations() map[string][][]interface{} { defer fake.hasTargetedOrganizationMutex.RUnlock() fake.hasTargetedSpaceMutex.RLock() defer fake.hasTargetedSpaceMutex.RUnlock() + fake.isCFOnK8sMutex.RLock() + defer fake.isCFOnK8sMutex.RUnlock() fake.refreshTokenMutex.RLock() defer fake.refreshTokenMutex.RUnlock() fake.targetedOrganizationNameMutex.RLock() diff --git a/actor/sharedaction/sharedactionfakes/fake_log_cache_client.go b/actor/sharedaction/sharedactionfakes/fake_log_cache_client.go index 948037d8ca0..ac0cf83dfa7 100644 --- a/actor/sharedaction/sharedactionfakes/fake_log_cache_client.go +++ b/actor/sharedaction/sharedactionfakes/fake_log_cache_client.go @@ -8,7 +8,7 @@ import ( "code.cloudfoundry.org/cli/actor/sharedaction" client "code.cloudfoundry.org/go-log-cache" - "code.cloudfoundry.org/go-loggregator/rpc/loggregator_v2" + "code.cloudfoundry.org/go-loggregator/v8/rpc/loggregator_v2" ) type FakeLogCacheClient struct { diff --git a/actor/v7action/actor.go b/actor/v7action/actor.go index 6a5cf533f0b..6fb6cbe0a35 100644 --- a/actor/v7action/actor.go +++ b/actor/v7action/actor.go @@ -2,6 +2,9 @@ package v7action import ( + "code.cloudfoundry.org/cli/api/uaa/constant" + "code.cloudfoundry.org/cli/cf/configuration/coreconfig" + "code.cloudfoundry.org/cli/util/configv3" "code.cloudfoundry.org/clock" ) @@ -16,6 +19,12 @@ const ( // Warnings is a list of warnings returned back from the cloud controller type Warnings []string +type AuthActor interface { + Authenticate(credentials map[string]string, origin string, grantType constant.GrantType) error + GetLoginPrompts() (map[string]coreconfig.AuthPrompt, error) + GetCurrentUser() (configv3.User, error) +} + // Actor represents a V7 actor. type Actor struct { CloudControllerClient CloudControllerClient @@ -24,6 +33,8 @@ type Actor struct { UAAClient UAAClient RoutingClient RoutingClient Clock clock.Clock + + AuthActor } // NewActor returns a new V7 actor. @@ -35,6 +46,11 @@ func NewActor( routingClient RoutingClient, clk clock.Clock, ) *Actor { + authActor := NewDefaultAuthActor(config, uaaClient) + if config != nil && config.IsCFOnK8s() { + authActor = NewKubernetesAuthActor(config, NewDefaultKubernetesConfigGetter(), client) + } + return &Actor{ CloudControllerClient: client, Config: config, @@ -42,5 +58,6 @@ func NewActor( UAAClient: uaaClient, RoutingClient: routingClient, Clock: clk, + AuthActor: authActor, } } diff --git a/actor/v7action/auth.go b/actor/v7action/auth.go index 3acbb46adc4..c69d4836a90 100644 --- a/actor/v7action/auth.go +++ b/actor/v7action/auth.go @@ -9,38 +9,51 @@ import ( "code.cloudfoundry.org/cli/actor/actionerror" "code.cloudfoundry.org/cli/api/uaa/constant" "code.cloudfoundry.org/cli/cf/configuration/coreconfig" + "code.cloudfoundry.org/cli/util/configv3" ) -func (actor Actor) Authenticate(credentials map[string]string, origin string, grantType constant.GrantType) error { - if grantType == constant.GrantTypePassword && actor.Config.UAAGrantType() == string(constant.GrantTypeClientCredentials) { +type defaultAuthActor struct { + config Config + uaaClient UAAClient +} + +func NewDefaultAuthActor(config Config, uaaClient UAAClient) AuthActor { + return &defaultAuthActor{ + config: config, + uaaClient: uaaClient, + } +} + +func (actor defaultAuthActor) Authenticate(credentials map[string]string, origin string, grantType constant.GrantType) error { + if grantType == constant.GrantTypePassword && actor.config.UAAGrantType() == string(constant.GrantTypeClientCredentials) { return actionerror.PasswordGrantTypeLogoutRequiredError{} } - actor.Config.UnsetOrganizationAndSpaceInformation() - accessToken, refreshToken, err := actor.UAAClient.Authenticate(credentials, origin, grantType) + actor.config.UnsetOrganizationAndSpaceInformation() + accessToken, refreshToken, err := actor.uaaClient.Authenticate(credentials, origin, grantType) if err != nil { - actor.Config.SetTokenInformation("", "", "") + actor.config.SetTokenInformation("", "", "") return err } accessToken = fmt.Sprintf("bearer %s", accessToken) - actor.Config.SetTokenInformation(accessToken, refreshToken, "") + actor.config.SetTokenInformation(accessToken, refreshToken, "") if grantType == constant.GrantTypePassword { - actor.Config.SetUAAGrantType("") + actor.config.SetUAAGrantType("") } else { - actor.Config.SetUAAGrantType(string(grantType)) + actor.config.SetUAAGrantType(string(grantType)) } if grantType == constant.GrantTypeClientCredentials { - actor.Config.SetUAAClientCredentials(credentials["client_id"], "") + actor.config.SetUAAClientCredentials(credentials["client_id"], "") } return nil } -func (actor Actor) GetLoginPrompts() (map[string]coreconfig.AuthPrompt, error) { - rawPrompts, err := actor.UAAClient.GetLoginPrompts() +func (actor defaultAuthActor) GetLoginPrompts() (map[string]coreconfig.AuthPrompt, error) { + rawPrompts, err := actor.uaaClient.GetLoginPrompts() if err != nil { return nil, err } @@ -56,6 +69,10 @@ func (actor Actor) GetLoginPrompts() (map[string]coreconfig.AuthPrompt, error) { return prompts, nil } +func (actor defaultAuthActor) GetCurrentUser() (configv3.User, error) { + return actor.config.CurrentUser() +} + // TODO: error check this in future stories func (actor Actor) RevokeAccessAndRefreshTokens() error { accessToken := actor.Config.AccessToken() @@ -75,7 +92,6 @@ func (actor Actor) isTokenRevocable(token string) bool { } jsonPayload, err := base64.RawURLEncoding.DecodeString(segments[1]) - if err != nil { return false } diff --git a/actor/v7action/auth_test.go b/actor/v7action/auth_test.go index 66f68058673..1949fe81838 100644 --- a/actor/v7action/auth_test.go +++ b/actor/v7action/auth_test.go @@ -7,24 +7,25 @@ import ( . "code.cloudfoundry.org/cli/actor/v7action" "code.cloudfoundry.org/cli/actor/v7action/v7actionfakes" "code.cloudfoundry.org/cli/api/uaa/constant" + "code.cloudfoundry.org/cli/util/configv3" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) -var _ = Describe("Auth Actions", func() { +var _ = Describe("Default Auth Actions", func() { var ( - actor *Actor - fakeCloudControllerClient *v7actionfakes.FakeCloudControllerClient - fakeUAAClient *v7actionfakes.FakeUAAClient - fakeConfig *v7actionfakes.FakeConfig - creds map[string]string + actor *Actor + fakeConfig *v7actionfakes.FakeConfig + fakeUAAClient *v7actionfakes.FakeUAAClient + creds map[string]string ) BeforeEach(func() { - fakeCloudControllerClient = new(v7actionfakes.FakeCloudControllerClient) - fakeUAAClient = new(v7actionfakes.FakeUAAClient) fakeConfig = new(v7actionfakes.FakeConfig) - actor = NewActor(fakeCloudControllerClient, fakeConfig, nil, fakeUAAClient, nil, nil) + fakeUAAClient = new(v7actionfakes.FakeUAAClient) + + fakeConfig.IsCFOnK8sReturns(false) + actor = NewActor(nil, fakeConfig, nil, fakeUAAClient, nil, nil) creds = map[string]string{ "client_id": "some-username", "client_secret": "some-password", @@ -172,7 +173,6 @@ var _ = Describe("Auth Actions", func() { }) When("the token is revokable", func() { - It("calls the UAA to revoke refresh and access tokens", func() { Expect(fakeUAAClient.RevokeCallCount()).To(Equal(2)) @@ -193,4 +193,23 @@ var _ = Describe("Auth Actions", func() { }) }) + Describe("Get Current User", func() { + var ( + user configv3.User + err error + ) + + JustBeforeEach(func() { + user, err = actor.GetCurrentUser() + }) + + BeforeEach(func() { + fakeConfig.CurrentUserReturns(configv3.User{Name: "jim"}, nil) + }) + + It("delegates to the injected config", func() { + Expect(err).NotTo(HaveOccurred()) + Expect(user.Name).To(Equal("jim")) + }) + }) }) diff --git a/actor/v7action/cloud_controller_client.go b/actor/v7action/cloud_controller_client.go index 35ff47380d9..e7f87fab036 100644 --- a/actor/v7action/cloud_controller_client.go +++ b/actor/v7action/cloud_controller_client.go @@ -186,6 +186,7 @@ type CloudControllerClient interface { UploadBuildpack(buildpackGUID string, buildpackPath string, buildpack io.Reader, buildpackLength int64) (ccv3.JobURL, ccv3.Warnings, error) UploadDropletBits(dropletGUID string, dropletPath string, droplet io.Reader, dropletLength int64) (ccv3.JobURL, ccv3.Warnings, error) UploadPackage(pkg resources.Package, zipFilepath string) (resources.Package, ccv3.Warnings, error) + WhoAmI() (resources.K8sUser, ccv3.Warnings, error) servicePlanVisibilityClient } diff --git a/actor/v7action/config.go b/actor/v7action/config.go index b1eaafee9f2..8c4eb01020a 100644 --- a/actor/v7action/config.go +++ b/actor/v7action/config.go @@ -11,6 +11,7 @@ import ( type Config interface { AccessToken() string APIVersion() string + CurrentUser() (configv3.User, error) DialTimeout() time.Duration PollingInterval() time.Duration RefreshToken() string @@ -27,4 +28,6 @@ type Config interface { Target() string UAAGrantType() string UnsetOrganizationAndSpaceInformation() + SetKubernetesAuthInfo(authInfo string) + IsCFOnK8s() bool } diff --git a/actor/v7action/droplet_test.go b/actor/v7action/droplet_test.go index 72f0e78a577..f477c283623 100644 --- a/actor/v7action/droplet_test.go +++ b/actor/v7action/droplet_test.go @@ -600,7 +600,7 @@ var _ = Describe("Droplet Actions", func() { }) When("the upload returns an error", func() { - var uploadErr = errors.New("upload failed") + uploadErr := errors.New("upload failed") BeforeEach(func() { fakeCloudControllerClient.UploadDropletBitsReturns( @@ -617,7 +617,7 @@ var _ = Describe("Droplet Actions", func() { }) When("the upload job fails eventually", func() { - var jobErr = errors.New("job failed") + jobErr := errors.New("job failed") BeforeEach(func() { fakeCloudControllerClient.UploadDropletBitsReturns( diff --git a/actor/v7action/k8s_auth.go b/actor/v7action/k8s_auth.go new file mode 100644 index 00000000000..bbbfadb9059 --- /dev/null +++ b/actor/v7action/k8s_auth.go @@ -0,0 +1,89 @@ +package v7action + +import ( + "errors" + "fmt" + "sort" + + "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" + "code.cloudfoundry.org/cli/api/uaa/constant" + "code.cloudfoundry.org/cli/cf/configuration/coreconfig" + "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/configv3" + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" +) + +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . KubernetesConfigGetter + +type KubernetesConfigGetter interface { + Get() (*clientcmdapi.Config, error) +} + +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . WhoAmIer + +type WhoAmIer interface { + WhoAmI() (resources.K8sUser, ccv3.Warnings, error) +} + +type DefaultKubernetesConfigGetter struct{} + +func NewDefaultKubernetesConfigGetter() DefaultKubernetesConfigGetter { + return DefaultKubernetesConfigGetter{} +} + +func (c DefaultKubernetesConfigGetter) Get() (*clientcmdapi.Config, error) { + pathOpts := clientcmd.NewDefaultPathOptions() + return pathOpts.GetStartingConfig() +} + +type kubernetesAuthActor struct { + config Config + k8sConfigGetter KubernetesConfigGetter + whoAmIer WhoAmIer +} + +func NewKubernetesAuthActor(config Config, k8sConfigGetter KubernetesConfigGetter, whoAmIer WhoAmIer) AuthActor { + return &kubernetesAuthActor{ + config: config, + k8sConfigGetter: k8sConfigGetter, + whoAmIer: whoAmIer, + } +} + +func (actor kubernetesAuthActor) Authenticate(credentials map[string]string, origin string, grantType constant.GrantType) error { + actor.config.SetKubernetesAuthInfo(credentials["k8s-auth-info"]) + return nil +} + +func (actor kubernetesAuthActor) GetLoginPrompts() (map[string]coreconfig.AuthPrompt, error) { + conf, err := actor.k8sConfigGetter.Get() + if err != nil { + return nil, err + } + + if len(conf.AuthInfos) == 0 { + return nil, errors.New("no kubernetes authentication infos configured") + } + + var prompts []string + for authInfo := range conf.AuthInfos { + prompts = append(prompts, authInfo) + } + sort.Strings(prompts) + + return map[string]coreconfig.AuthPrompt{"k8s-auth-info": { + Type: coreconfig.AuthPromptTypeMenu, + Entries: prompts, + DisplayName: "Choose your Kubernetes authentication info", + }}, nil +} + +func (actor kubernetesAuthActor) GetCurrentUser() (configv3.User, error) { + user, _, err := actor.whoAmIer.WhoAmI() + if err != nil { + return configv3.User{}, fmt.Errorf("calling /whoami endpoint failed: %w", err) + } + + return configv3.User{Name: user.Name}, nil +} diff --git a/actor/v7action/k8s_auth_test.go b/actor/v7action/k8s_auth_test.go new file mode 100644 index 00000000000..91ee1c6edaf --- /dev/null +++ b/actor/v7action/k8s_auth_test.go @@ -0,0 +1,121 @@ +package v7action_test + +import ( + "errors" + + "code.cloudfoundry.org/cli/actor/v7action" + "code.cloudfoundry.org/cli/actor/v7action/v7actionfakes" + "code.cloudfoundry.org/cli/api/uaa/constant" + "code.cloudfoundry.org/cli/cf/configuration/coreconfig" + "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/configv3" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" +) + +var _ = Describe("KubernetesAuthActor", func() { + var ( + k8sAuthActor v7action.AuthActor + k8sConfigGetter *v7actionfakes.FakeKubernetesConfigGetter + whoAmIer *v7actionfakes.FakeWhoAmIer + config *v7actionfakes.FakeConfig + err error + ) + + BeforeEach(func() { + config = new(v7actionfakes.FakeConfig) + k8sConfigGetter = new(v7actionfakes.FakeKubernetesConfigGetter) + k8sConfigGetter.GetReturns(&clientcmdapi.Config{ + AuthInfos: map[string]*clientcmdapi.AuthInfo{"foo": {}, "bar": {}}, + }, nil) + whoAmIer = new(v7actionfakes.FakeWhoAmIer) + k8sAuthActor = v7action.NewKubernetesAuthActor(config, k8sConfigGetter, whoAmIer) + }) + + Describe("Authenticate", func() { + JustBeforeEach(func() { + err = k8sAuthActor.Authenticate(map[string]string{"k8s-auth-info": "bar"}, "", constant.GrantTypePassword) + }) + + It("sets the Kubernetes auth-info", func() { + Expect(err).NotTo(HaveOccurred()) + Expect(config.SetKubernetesAuthInfoCallCount()).To(Equal(1)) + Expect(config.SetKubernetesAuthInfoArgsForCall(0)).To(Equal("bar")) + }) + }) + + Describe("GetLoginPrompts", func() { + var authPrompts map[string]coreconfig.AuthPrompt + + JustBeforeEach(func() { + authPrompts, err = k8sAuthActor.GetLoginPrompts() + }) + + It("returns an auth prompt menu", func() { + Expect(err).NotTo(HaveOccurred()) + Expect(authPrompts).To(HaveLen(1)) + Expect(authPrompts).To(HaveKey("k8s-auth-info")) + + authPrompt := authPrompts["k8s-auth-info"] + Expect(authPrompt.Type).To(Equal(coreconfig.AuthPromptTypeMenu)) + Expect(authPrompt.DisplayName).To(Equal("Choose your Kubernetes authentication info")) + Expect(authPrompt.Entries).To(ConsistOf("foo", "bar")) + }) + + It("sorts the entries", func() { + authPrompt := authPrompts["k8s-auth-info"] + Expect(authPrompt.Entries).To(Equal([]string{"bar", "foo"})) + }) + + When("getting the k8s config fails", func() { + BeforeEach(func() { + k8sConfigGetter.GetReturns(nil, errors.New("oomph!")) + }) + + It("returns the error", func() { + Expect(err).To(MatchError("oomph!")) + }) + }) + + When("no auth infos are in the k8s config", func() { + BeforeEach(func() { + k8sConfigGetter.GetReturns(&clientcmdapi.Config{}, nil) + }) + + It("returns an error", func() { + Expect(err).To(MatchError("no kubernetes authentication infos configured")) + }) + }) + }) + + Describe("Get Current User", func() { + var ( + user configv3.User + err error + ) + + BeforeEach(func() { + whoAmIer.WhoAmIReturns(resources.K8sUser{Name: "bob", Kind: "User"}, nil, nil) + }) + + JustBeforeEach(func() { + user, err = k8sAuthActor.GetCurrentUser() + }) + + It("uses the WhoAmI function to get the real current user name", func() { + Expect(err).NotTo(HaveOccurred()) + Expect(user.Name).To(Equal("bob")) + }) + + When("calling the whoami endpoint fails", func() { + BeforeEach(func() { + whoAmIer.WhoAmIReturns(resources.K8sUser{}, nil, errors.New("boom!")) + }) + + It("returns an error", func() { + Expect(err).To(MatchError(ContainSubstring("boom!"))) + }) + }) + }) +}) diff --git a/actor/v7action/label_test.go b/actor/v7action/label_test.go index 4b9348cb0f9..df3a573ad40 100644 --- a/actor/v7action/label_test.go +++ b/actor/v7action/label_test.go @@ -959,7 +959,8 @@ var _ = Describe("labels", func() { GUID: "some-guid", Metadata: &resources.Metadata{ Labels: expectedLabels, - }}}, + }, + }}, ccv3.Warnings([]string{"warning-1", "warning-2"}), nil, ) @@ -1122,7 +1123,8 @@ var _ = Describe("labels", func() { GUID: "some-guid", Metadata: &resources.Metadata{ Labels: expectedLabels, - }}}, + }, + }}, ccv3.Warnings([]string{"warning-1", "warning-2"}), nil, ) @@ -1204,7 +1206,8 @@ var _ = Describe("labels", func() { Name: resourceName, Metadata: &resources.Metadata{ Labels: expectedLabels, - }}}, + }, + }}, []string{"warning-1", "warning-2"}, nil, ) @@ -1422,7 +1425,8 @@ var _ = Describe("labels", func() { Name: resourceName, Metadata: &resources.Metadata{ Labels: expectedLabels, - }}}, + }, + }}, []string{"warning-1", "warning-2"}, nil, ) diff --git a/actor/v7action/logging_test.go b/actor/v7action/logging_test.go index c7ff9e75c3f..8cefdb9a6b1 100644 --- a/actor/v7action/logging_test.go +++ b/actor/v7action/logging_test.go @@ -12,7 +12,7 @@ import ( "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" "code.cloudfoundry.org/cli/resources" logcache "code.cloudfoundry.org/go-log-cache" - "code.cloudfoundry.org/go-loggregator/rpc/loggregator_v2" + "code.cloudfoundry.org/go-loggregator/v8/rpc/loggregator_v2" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) diff --git a/actor/v7action/security_group_test.go b/actor/v7action/security_group_test.go index 02aa8f691d6..ed0a72500eb 100644 --- a/actor/v7action/security_group_test.go +++ b/actor/v7action/security_group_test.go @@ -30,7 +30,6 @@ var _ = Describe("Security Group Actions", func() { BeforeEach(func() { fakeCloudControllerClient = new(v7actionfakes.FakeCloudControllerClient) actor = NewActor(fakeCloudControllerClient, nil, nil, nil, nil, nil) - }) Describe("BindSecurityGroupToSpaces", func() { diff --git a/actor/v7action/space_test.go b/actor/v7action/space_test.go index 4dbe54cc656..b3f67ab13b7 100644 --- a/actor/v7action/space_test.go +++ b/actor/v7action/space_test.go @@ -265,10 +265,12 @@ var _ = Describe("Space", func() { When("the cloud controller returns a space with a quota relationship", func() { BeforeEach(func() { fakeCloudControllerClient.GetSpacesReturns( - []resources.Space{{GUID: "some-space-guid", Name: spaceName, + []resources.Space{{ + GUID: "some-space-guid", Name: spaceName, Relationships: resources.Relationships{ constant.RelationshipTypeQuota: resources.Relationship{GUID: "some-space-quota-guid"}, - }}}, + }, + }}, ccv3.IncludedResources{}, ccv3.Warnings{"some-space-warning"}, nil) }) diff --git a/actor/v7action/stack_test.go b/actor/v7action/stack_test.go index 39d95a29f17..aaab0d4aa00 100644 --- a/actor/v7action/stack_test.go +++ b/actor/v7action/stack_test.go @@ -25,7 +25,6 @@ var _ = Describe("Stack", func() { }) Describe("Get stack by name", func() { - var expectedErr error var err error var warnings Warnings diff --git a/actor/v7action/target.go b/actor/v7action/target.go index 99ab47ba63a..a63a02711c2 100644 --- a/actor/v7action/target.go +++ b/actor/v7action/target.go @@ -31,9 +31,11 @@ func (actor Actor) SetTarget(settings TargetSettings) (Warnings, error) { Routing: rootInfo.Routing(), SkipSSLValidation: settings.SkipSSLValidation, UAA: rootInfo.UAA(), + CFOnK8s: rootInfo.CFOnK8s, }) actor.Config.SetTokenInformation("", "", "") + actor.Config.SetKubernetesAuthInfo("") return allWarnings, nil } @@ -42,4 +44,5 @@ func (actor Actor) SetTarget(settings TargetSettings) (Warnings, error) { func (actor Actor) ClearTarget() { actor.Config.SetTargetInformation(configv3.TargetInformationArgs{}) actor.Config.SetTokenInformation("", "", "") + actor.Config.SetKubernetesAuthInfo("") } diff --git a/actor/v7action/target_test.go b/actor/v7action/target_test.go index b09c74994a5..54123fd35ce 100644 --- a/actor/v7action/target_test.go +++ b/actor/v7action/target_test.go @@ -25,7 +25,6 @@ var _ = Describe("Targeting", func() { BeforeEach(func() { actor, fakeCloudControllerClient, fakeConfig, _, _, _, _ = NewTestActor() - }) Describe("SetTarget", func() { @@ -120,6 +119,7 @@ var _ = Describe("Targeting", func() { Expect(targetInfoArgs.LogCache).To(Equal(expectedLogCache)) Expect(targetInfoArgs.Routing).To(Equal(expectedRouting)) Expect(targetInfoArgs.SkipSSLValidation).To(Equal(skipSSLValidation)) + Expect(targetInfoArgs.CFOnK8s).To(BeFalse()) }) It("clears all the token information", func() { @@ -131,10 +131,29 @@ var _ = Describe("Targeting", func() { Expect(sshOAuthClient).To(BeEmpty()) }) + It("clears the Kubernetes auth-info", func() { + Expect(fakeConfig.SetKubernetesAuthInfoCallCount()).To(Equal(1)) + authInfo := fakeConfig.SetKubernetesAuthInfoArgsForCall(0) + + Expect(authInfo).To(BeEmpty()) + }) + It("succeeds and returns all warnings", func() { Expect(err).ToNot(HaveOccurred()) Expect(warnings).To(ConsistOf(Warnings{"info-warning"})) }) + + When("deployed on Kubernetes", func() { + BeforeEach(func() { + fakeCloudControllerClient.GetInfoReturns(ccv3.Info{CFOnK8s: true}, nil, nil) + }) + + It("sets the CFOnK8s target information", func() { + Expect(fakeConfig.SetTargetInformationCallCount()).To(Equal(1)) + targetInfoArgs := fakeConfig.SetTargetInformationArgsForCall(0) + Expect(targetInfoArgs.CFOnK8s).To(BeTrue()) + }) + }) }) Describe("ClearTarget", func() { @@ -164,5 +183,14 @@ var _ = Describe("Targeting", func() { Expect(refreshToken).To(BeEmpty()) Expect(sshOAuthClient).To(BeEmpty()) }) + + It("clears the Kubernetes auth-info", func() { + actor.ClearTarget() + + Expect(fakeConfig.SetKubernetesAuthInfoCallCount()).To(Equal(1)) + authInfo := fakeConfig.SetKubernetesAuthInfoArgsForCall(0) + + Expect(authInfo).To(BeEmpty()) + }) }) }) diff --git a/actor/v7action/v7action_suite_test.go b/actor/v7action/v7action_suite_test.go index 5d2a56804f8..675a860f222 100644 --- a/actor/v7action/v7action_suite_test.go +++ b/actor/v7action/v7action_suite_test.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" "strings" + "testing" "time" . "code.cloudfoundry.org/cli/actor/v7action" @@ -14,8 +15,6 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" log "github.com/sirupsen/logrus" - - "testing" ) func TestV3Action(t *testing.T) { diff --git a/actor/v7action/v7actionfakes/fake_cloud_controller_client.go b/actor/v7action/v7actionfakes/fake_cloud_controller_client.go index ca4a7e21d35..0c37e114ddf 100644 --- a/actor/v7action/v7actionfakes/fake_cloud_controller_client.go +++ b/actor/v7action/v7actionfakes/fake_cloud_controller_client.go @@ -2665,6 +2665,20 @@ type FakeCloudControllerClient struct { result2 ccv3.Warnings result3 error } + WhoAmIStub func() (resources.K8sUser, ccv3.Warnings, error) + whoAmIMutex sync.RWMutex + whoAmIArgsForCall []struct { + } + whoAmIReturns struct { + result1 resources.K8sUser + result2 ccv3.Warnings + result3 error + } + whoAmIReturnsOnCall map[int]struct { + result1 resources.K8sUser + result2 ccv3.Warnings + result3 error + } invocations map[string][][]interface{} invocationsMutex sync.RWMutex } @@ -14232,6 +14246,64 @@ func (fake *FakeCloudControllerClient) UploadPackageReturnsOnCall(i int, result1 }{result1, result2, result3} } +func (fake *FakeCloudControllerClient) WhoAmI() (resources.K8sUser, ccv3.Warnings, error) { + fake.whoAmIMutex.Lock() + ret, specificReturn := fake.whoAmIReturnsOnCall[len(fake.whoAmIArgsForCall)] + fake.whoAmIArgsForCall = append(fake.whoAmIArgsForCall, struct { + }{}) + fake.recordInvocation("WhoAmI", []interface{}{}) + fake.whoAmIMutex.Unlock() + if fake.WhoAmIStub != nil { + return fake.WhoAmIStub() + } + if specificReturn { + return ret.result1, ret.result2, ret.result3 + } + fakeReturns := fake.whoAmIReturns + return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 +} + +func (fake *FakeCloudControllerClient) WhoAmICallCount() int { + fake.whoAmIMutex.RLock() + defer fake.whoAmIMutex.RUnlock() + return len(fake.whoAmIArgsForCall) +} + +func (fake *FakeCloudControllerClient) WhoAmICalls(stub func() (resources.K8sUser, ccv3.Warnings, error)) { + fake.whoAmIMutex.Lock() + defer fake.whoAmIMutex.Unlock() + fake.WhoAmIStub = stub +} + +func (fake *FakeCloudControllerClient) WhoAmIReturns(result1 resources.K8sUser, result2 ccv3.Warnings, result3 error) { + fake.whoAmIMutex.Lock() + defer fake.whoAmIMutex.Unlock() + fake.WhoAmIStub = nil + fake.whoAmIReturns = struct { + result1 resources.K8sUser + result2 ccv3.Warnings + result3 error + }{result1, result2, result3} +} + +func (fake *FakeCloudControllerClient) WhoAmIReturnsOnCall(i int, result1 resources.K8sUser, result2 ccv3.Warnings, result3 error) { + fake.whoAmIMutex.Lock() + defer fake.whoAmIMutex.Unlock() + fake.WhoAmIStub = nil + if fake.whoAmIReturnsOnCall == nil { + fake.whoAmIReturnsOnCall = make(map[int]struct { + result1 resources.K8sUser + result2 ccv3.Warnings + result3 error + }) + } + fake.whoAmIReturnsOnCall[i] = struct { + result1 resources.K8sUser + result2 ccv3.Warnings + result3 error + }{result1, result2, result3} +} + func (fake *FakeCloudControllerClient) Invocations() map[string][][]interface{} { fake.invocationsMutex.RLock() defer fake.invocationsMutex.RUnlock() @@ -14585,6 +14657,8 @@ func (fake *FakeCloudControllerClient) Invocations() map[string][][]interface{} defer fake.uploadDropletBitsMutex.RUnlock() fake.uploadPackageMutex.RLock() defer fake.uploadPackageMutex.RUnlock() + fake.whoAmIMutex.RLock() + defer fake.whoAmIMutex.RUnlock() copiedInvocations := map[string][][]interface{}{} for key, value := range fake.invocations { copiedInvocations[key] = value diff --git a/actor/v7action/v7actionfakes/fake_config.go b/actor/v7action/v7actionfakes/fake_config.go index d9e05fd823d..9bbf83bc714 100644 --- a/actor/v7action/v7actionfakes/fake_config.go +++ b/actor/v7action/v7actionfakes/fake_config.go @@ -30,6 +30,18 @@ type FakeConfig struct { accessTokenReturnsOnCall map[int]struct { result1 string } + CurrentUserStub func() (configv3.User, error) + currentUserMutex sync.RWMutex + currentUserArgsForCall []struct { + } + currentUserReturns struct { + result1 configv3.User + result2 error + } + currentUserReturnsOnCall map[int]struct { + result1 configv3.User + result2 error + } DialTimeoutStub func() time.Duration dialTimeoutMutex sync.RWMutex dialTimeoutArgsForCall []struct { @@ -40,6 +52,16 @@ type FakeConfig struct { dialTimeoutReturnsOnCall map[int]struct { result1 time.Duration } + IsCFOnK8sStub func() bool + isCFOnK8sMutex sync.RWMutex + isCFOnK8sArgsForCall []struct { + } + isCFOnK8sReturns struct { + result1 bool + } + isCFOnK8sReturnsOnCall map[int]struct { + result1 bool + } PollingIntervalStub func() time.Duration pollingIntervalMutex sync.RWMutex pollingIntervalArgsForCall []struct { @@ -75,6 +97,11 @@ type FakeConfig struct { setAccessTokenArgsForCall []struct { arg1 string } + SetKubernetesAuthInfoStub func(string) + setKubernetesAuthInfoMutex sync.RWMutex + setKubernetesAuthInfoArgsForCall []struct { + arg1 string + } SetRefreshTokenStub func(string) setRefreshTokenMutex sync.RWMutex setRefreshTokenArgsForCall []struct { @@ -265,6 +292,61 @@ func (fake *FakeConfig) AccessTokenReturnsOnCall(i int, result1 string) { }{result1} } +func (fake *FakeConfig) CurrentUser() (configv3.User, error) { + fake.currentUserMutex.Lock() + ret, specificReturn := fake.currentUserReturnsOnCall[len(fake.currentUserArgsForCall)] + fake.currentUserArgsForCall = append(fake.currentUserArgsForCall, struct { + }{}) + fake.recordInvocation("CurrentUser", []interface{}{}) + fake.currentUserMutex.Unlock() + if fake.CurrentUserStub != nil { + return fake.CurrentUserStub() + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.currentUserReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeConfig) CurrentUserCallCount() int { + fake.currentUserMutex.RLock() + defer fake.currentUserMutex.RUnlock() + return len(fake.currentUserArgsForCall) +} + +func (fake *FakeConfig) CurrentUserCalls(stub func() (configv3.User, error)) { + fake.currentUserMutex.Lock() + defer fake.currentUserMutex.Unlock() + fake.CurrentUserStub = stub +} + +func (fake *FakeConfig) CurrentUserReturns(result1 configv3.User, result2 error) { + fake.currentUserMutex.Lock() + defer fake.currentUserMutex.Unlock() + fake.CurrentUserStub = nil + fake.currentUserReturns = struct { + result1 configv3.User + result2 error + }{result1, result2} +} + +func (fake *FakeConfig) CurrentUserReturnsOnCall(i int, result1 configv3.User, result2 error) { + fake.currentUserMutex.Lock() + defer fake.currentUserMutex.Unlock() + fake.CurrentUserStub = nil + if fake.currentUserReturnsOnCall == nil { + fake.currentUserReturnsOnCall = make(map[int]struct { + result1 configv3.User + result2 error + }) + } + fake.currentUserReturnsOnCall[i] = struct { + result1 configv3.User + result2 error + }{result1, result2} +} + func (fake *FakeConfig) DialTimeout() time.Duration { fake.dialTimeoutMutex.Lock() ret, specificReturn := fake.dialTimeoutReturnsOnCall[len(fake.dialTimeoutArgsForCall)] @@ -317,6 +399,58 @@ func (fake *FakeConfig) DialTimeoutReturnsOnCall(i int, result1 time.Duration) { }{result1} } +func (fake *FakeConfig) IsCFOnK8s() bool { + fake.isCFOnK8sMutex.Lock() + ret, specificReturn := fake.isCFOnK8sReturnsOnCall[len(fake.isCFOnK8sArgsForCall)] + fake.isCFOnK8sArgsForCall = append(fake.isCFOnK8sArgsForCall, struct { + }{}) + fake.recordInvocation("IsCFOnK8s", []interface{}{}) + fake.isCFOnK8sMutex.Unlock() + if fake.IsCFOnK8sStub != nil { + return fake.IsCFOnK8sStub() + } + if specificReturn { + return ret.result1 + } + fakeReturns := fake.isCFOnK8sReturns + return fakeReturns.result1 +} + +func (fake *FakeConfig) IsCFOnK8sCallCount() int { + fake.isCFOnK8sMutex.RLock() + defer fake.isCFOnK8sMutex.RUnlock() + return len(fake.isCFOnK8sArgsForCall) +} + +func (fake *FakeConfig) IsCFOnK8sCalls(stub func() bool) { + fake.isCFOnK8sMutex.Lock() + defer fake.isCFOnK8sMutex.Unlock() + fake.IsCFOnK8sStub = stub +} + +func (fake *FakeConfig) IsCFOnK8sReturns(result1 bool) { + fake.isCFOnK8sMutex.Lock() + defer fake.isCFOnK8sMutex.Unlock() + fake.IsCFOnK8sStub = nil + fake.isCFOnK8sReturns = struct { + result1 bool + }{result1} +} + +func (fake *FakeConfig) IsCFOnK8sReturnsOnCall(i int, result1 bool) { + fake.isCFOnK8sMutex.Lock() + defer fake.isCFOnK8sMutex.Unlock() + fake.IsCFOnK8sStub = nil + if fake.isCFOnK8sReturnsOnCall == nil { + fake.isCFOnK8sReturnsOnCall = make(map[int]struct { + result1 bool + }) + } + fake.isCFOnK8sReturnsOnCall[i] = struct { + result1 bool + }{result1} +} + func (fake *FakeConfig) PollingInterval() time.Duration { fake.pollingIntervalMutex.Lock() ret, specificReturn := fake.pollingIntervalReturnsOnCall[len(fake.pollingIntervalArgsForCall)] @@ -504,6 +638,37 @@ func (fake *FakeConfig) SetAccessTokenArgsForCall(i int) string { return argsForCall.arg1 } +func (fake *FakeConfig) SetKubernetesAuthInfo(arg1 string) { + fake.setKubernetesAuthInfoMutex.Lock() + fake.setKubernetesAuthInfoArgsForCall = append(fake.setKubernetesAuthInfoArgsForCall, struct { + arg1 string + }{arg1}) + fake.recordInvocation("SetKubernetesAuthInfo", []interface{}{arg1}) + fake.setKubernetesAuthInfoMutex.Unlock() + if fake.SetKubernetesAuthInfoStub != nil { + fake.SetKubernetesAuthInfoStub(arg1) + } +} + +func (fake *FakeConfig) SetKubernetesAuthInfoCallCount() int { + fake.setKubernetesAuthInfoMutex.RLock() + defer fake.setKubernetesAuthInfoMutex.RUnlock() + return len(fake.setKubernetesAuthInfoArgsForCall) +} + +func (fake *FakeConfig) SetKubernetesAuthInfoCalls(stub func(string)) { + fake.setKubernetesAuthInfoMutex.Lock() + defer fake.setKubernetesAuthInfoMutex.Unlock() + fake.SetKubernetesAuthInfoStub = stub +} + +func (fake *FakeConfig) SetKubernetesAuthInfoArgsForCall(i int) string { + fake.setKubernetesAuthInfoMutex.RLock() + defer fake.setKubernetesAuthInfoMutex.RUnlock() + argsForCall := fake.setKubernetesAuthInfoArgsForCall[i] + return argsForCall.arg1 +} + func (fake *FakeConfig) SetRefreshToken(arg1 string) { fake.setRefreshTokenMutex.Lock() fake.setRefreshTokenArgsForCall = append(fake.setRefreshTokenArgsForCall, struct { @@ -952,8 +1117,12 @@ func (fake *FakeConfig) Invocations() map[string][][]interface{} { defer fake.aPIVersionMutex.RUnlock() fake.accessTokenMutex.RLock() defer fake.accessTokenMutex.RUnlock() + fake.currentUserMutex.RLock() + defer fake.currentUserMutex.RUnlock() fake.dialTimeoutMutex.RLock() defer fake.dialTimeoutMutex.RUnlock() + fake.isCFOnK8sMutex.RLock() + defer fake.isCFOnK8sMutex.RUnlock() fake.pollingIntervalMutex.RLock() defer fake.pollingIntervalMutex.RUnlock() fake.refreshTokenMutex.RLock() @@ -962,6 +1131,8 @@ func (fake *FakeConfig) Invocations() map[string][][]interface{} { defer fake.sSHOAuthClientMutex.RUnlock() fake.setAccessTokenMutex.RLock() defer fake.setAccessTokenMutex.RUnlock() + fake.setKubernetesAuthInfoMutex.RLock() + defer fake.setKubernetesAuthInfoMutex.RUnlock() fake.setRefreshTokenMutex.RLock() defer fake.setRefreshTokenMutex.RUnlock() fake.setTargetInformationMutex.RLock() diff --git a/actor/v7action/v7actionfakes/fake_kubernetes_config_getter.go b/actor/v7action/v7actionfakes/fake_kubernetes_config_getter.go new file mode 100644 index 00000000000..f22933d1bb8 --- /dev/null +++ b/actor/v7action/v7actionfakes/fake_kubernetes_config_getter.go @@ -0,0 +1,107 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package v7actionfakes + +import ( + "sync" + + "code.cloudfoundry.org/cli/actor/v7action" + "k8s.io/client-go/tools/clientcmd/api" +) + +type FakeKubernetesConfigGetter struct { + GetStub func() (*api.Config, error) + getMutex sync.RWMutex + getArgsForCall []struct { + } + getReturns struct { + result1 *api.Config + result2 error + } + getReturnsOnCall map[int]struct { + result1 *api.Config + result2 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeKubernetesConfigGetter) Get() (*api.Config, error) { + fake.getMutex.Lock() + ret, specificReturn := fake.getReturnsOnCall[len(fake.getArgsForCall)] + fake.getArgsForCall = append(fake.getArgsForCall, struct { + }{}) + fake.recordInvocation("Get", []interface{}{}) + fake.getMutex.Unlock() + if fake.GetStub != nil { + return fake.GetStub() + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeKubernetesConfigGetter) GetCallCount() int { + fake.getMutex.RLock() + defer fake.getMutex.RUnlock() + return len(fake.getArgsForCall) +} + +func (fake *FakeKubernetesConfigGetter) GetCalls(stub func() (*api.Config, error)) { + fake.getMutex.Lock() + defer fake.getMutex.Unlock() + fake.GetStub = stub +} + +func (fake *FakeKubernetesConfigGetter) GetReturns(result1 *api.Config, result2 error) { + fake.getMutex.Lock() + defer fake.getMutex.Unlock() + fake.GetStub = nil + fake.getReturns = struct { + result1 *api.Config + result2 error + }{result1, result2} +} + +func (fake *FakeKubernetesConfigGetter) GetReturnsOnCall(i int, result1 *api.Config, result2 error) { + fake.getMutex.Lock() + defer fake.getMutex.Unlock() + fake.GetStub = nil + if fake.getReturnsOnCall == nil { + fake.getReturnsOnCall = make(map[int]struct { + result1 *api.Config + result2 error + }) + } + fake.getReturnsOnCall[i] = struct { + result1 *api.Config + result2 error + }{result1, result2} +} + +func (fake *FakeKubernetesConfigGetter) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.getMutex.RLock() + defer fake.getMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeKubernetesConfigGetter) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ v7action.KubernetesConfigGetter = new(FakeKubernetesConfigGetter) diff --git a/actor/v7action/v7actionfakes/fake_who_am_ier.go b/actor/v7action/v7actionfakes/fake_who_am_ier.go new file mode 100644 index 00000000000..0d1eb42bacc --- /dev/null +++ b/actor/v7action/v7actionfakes/fake_who_am_ier.go @@ -0,0 +1,113 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package v7actionfakes + +import ( + "sync" + + "code.cloudfoundry.org/cli/actor/v7action" + "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" + "code.cloudfoundry.org/cli/resources" +) + +type FakeWhoAmIer struct { + WhoAmIStub func() (resources.K8sUser, ccv3.Warnings, error) + whoAmIMutex sync.RWMutex + whoAmIArgsForCall []struct { + } + whoAmIReturns struct { + result1 resources.K8sUser + result2 ccv3.Warnings + result3 error + } + whoAmIReturnsOnCall map[int]struct { + result1 resources.K8sUser + result2 ccv3.Warnings + result3 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeWhoAmIer) WhoAmI() (resources.K8sUser, ccv3.Warnings, error) { + fake.whoAmIMutex.Lock() + ret, specificReturn := fake.whoAmIReturnsOnCall[len(fake.whoAmIArgsForCall)] + fake.whoAmIArgsForCall = append(fake.whoAmIArgsForCall, struct { + }{}) + fake.recordInvocation("WhoAmI", []interface{}{}) + fake.whoAmIMutex.Unlock() + if fake.WhoAmIStub != nil { + return fake.WhoAmIStub() + } + if specificReturn { + return ret.result1, ret.result2, ret.result3 + } + fakeReturns := fake.whoAmIReturns + return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 +} + +func (fake *FakeWhoAmIer) WhoAmICallCount() int { + fake.whoAmIMutex.RLock() + defer fake.whoAmIMutex.RUnlock() + return len(fake.whoAmIArgsForCall) +} + +func (fake *FakeWhoAmIer) WhoAmICalls(stub func() (resources.K8sUser, ccv3.Warnings, error)) { + fake.whoAmIMutex.Lock() + defer fake.whoAmIMutex.Unlock() + fake.WhoAmIStub = stub +} + +func (fake *FakeWhoAmIer) WhoAmIReturns(result1 resources.K8sUser, result2 ccv3.Warnings, result3 error) { + fake.whoAmIMutex.Lock() + defer fake.whoAmIMutex.Unlock() + fake.WhoAmIStub = nil + fake.whoAmIReturns = struct { + result1 resources.K8sUser + result2 ccv3.Warnings + result3 error + }{result1, result2, result3} +} + +func (fake *FakeWhoAmIer) WhoAmIReturnsOnCall(i int, result1 resources.K8sUser, result2 ccv3.Warnings, result3 error) { + fake.whoAmIMutex.Lock() + defer fake.whoAmIMutex.Unlock() + fake.WhoAmIStub = nil + if fake.whoAmIReturnsOnCall == nil { + fake.whoAmIReturnsOnCall = make(map[int]struct { + result1 resources.K8sUser + result2 ccv3.Warnings + result3 error + }) + } + fake.whoAmIReturnsOnCall[i] = struct { + result1 resources.K8sUser + result2 ccv3.Warnings + result3 error + }{result1, result2, result3} +} + +func (fake *FakeWhoAmIer) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.whoAmIMutex.RLock() + defer fake.whoAmIMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeWhoAmIer) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ v7action.WhoAmIer = new(FakeWhoAmIer) diff --git a/api/cloudcontroller/ccv3/info.go b/api/cloudcontroller/ccv3/info.go index 288d1060861..8a2e694a18c 100644 --- a/api/cloudcontroller/ccv3/info.go +++ b/api/cloudcontroller/ccv3/info.go @@ -39,7 +39,8 @@ type InfoLinks struct { // controller API. type Info struct { // Links is a list of top level Cloud Controller APIs. - Links InfoLinks `json:"links"` + Links InfoLinks `json:"links"` + CFOnK8s bool `json:"cf_on_k8s"` } // AppSSHEndpoint returns the HREF for SSHing into an app container. diff --git a/api/cloudcontroller/ccv3/info_test.go b/api/cloudcontroller/ccv3/info_test.go index b90c500218f..8f77db3ba96 100644 --- a/api/cloudcontroller/ccv3/info_test.go +++ b/api/cloudcontroller/ccv3/info_test.go @@ -18,7 +18,7 @@ var _ = Describe("Info", func() { client *Client rootRespondWith http.HandlerFunc - apis Info + info Info warnings Warnings executeErr error ) @@ -37,7 +37,7 @@ var _ = Describe("Info", func() { ), ) - apis, warnings, executeErr = client.GetInfo() + info, warnings, executeErr = client.GetInfo() }) Describe("when all requests are successful", func() { @@ -86,18 +86,29 @@ var _ = Describe("Info", func() { It("returns the CC Information", func() { Expect(executeErr).NotTo(HaveOccurred()) - Expect(apis.UAA()).To(Equal("https://uaa.bosh-lite.com")) - Expect(apis.Logging()).To(Equal("wss://doppler.bosh-lite.com:443")) - Expect(apis.NetworkPolicyV1()).To(Equal(fmt.Sprintf("%s/networking/v1/external", server.URL()))) - Expect(apis.AppSSHHostKeyFingerprint()).To(Equal("some-fingerprint")) - Expect(apis.AppSSHEndpoint()).To(Equal("ssh.bosh-lite.com:2222")) - Expect(apis.OAuthClient()).To(Equal("some-client")) + Expect(info.UAA()).To(Equal("https://uaa.bosh-lite.com")) + Expect(info.Logging()).To(Equal("wss://doppler.bosh-lite.com:443")) + Expect(info.NetworkPolicyV1()).To(Equal(fmt.Sprintf("%s/networking/v1/external", server.URL()))) + Expect(info.AppSSHHostKeyFingerprint()).To(Equal("some-fingerprint")) + Expect(info.AppSSHEndpoint()).To(Equal("ssh.bosh-lite.com:2222")) + Expect(info.OAuthClient()).To(Equal("some-client")) + Expect(info.CFOnK8s).To(BeFalse()) }) It("returns all warnings", func() { Expect(executeErr).NotTo(HaveOccurred()) Expect(warnings).To(ConsistOf("warning 1")) }) + + When("CF-on-K8s", func() { + BeforeEach(func() { + rootRespondWith = RespondWith(http.StatusOK, `{ "cf_on_k8s": true }`) + }) + + It("sets the CFOnK8s", func() { + Expect(info.CFOnK8s).To(BeTrue()) + }) + }) }) When("the cloud controller encounters an error", func() { diff --git a/api/cloudcontroller/ccv3/internal/api_routes.go b/api/cloudcontroller/ccv3/internal/api_routes.go index c69bd7a6e63..f1d637933f3 100644 --- a/api/cloudcontroller/ccv3/internal/api_routes.go +++ b/api/cloudcontroller/ccv3/internal/api_routes.go @@ -172,6 +172,7 @@ const ( PutTaskCancelRequest = "PutTaskCancel" SharePrivateDomainRequest = "SharePrivateDomainRequest" UnmapRouteRequest = "UnmapRoute" + WhoAmI = "WhoAmI" ) // APIRoutes is a list of routes used by the router to construct request URLs. @@ -339,4 +340,5 @@ var APIRoutes = map[string]Route{ GetUserRequest: {Path: "/v3/users/:user_guid", Method: http.MethodGet}, PostUserRequest: {Path: "/v3/users", Method: http.MethodPost}, DeleteUserRequest: {Path: "/v3/users/:user_guid", Method: http.MethodDelete}, + WhoAmI: {Path: "/whoami", Method: http.MethodGet}, } diff --git a/api/cloudcontroller/ccv3/user.go b/api/cloudcontroller/ccv3/user.go index 88412343e84..7b2aa8edb20 100644 --- a/api/cloudcontroller/ccv3/user.go +++ b/api/cloudcontroller/ccv3/user.go @@ -60,3 +60,14 @@ func (client *Client) GetUsers(query ...Query) ([]resources.User, Warnings, erro return users, warnings, err } + +func (client *Client) WhoAmI() (resources.K8sUser, Warnings, error) { + var user resources.K8sUser + + _, warnings, err := client.MakeRequest(RequestParams{ + RequestName: internal.WhoAmI, + ResponseBody: &user, + }) + + return user, warnings, err +} diff --git a/api/cloudcontroller/ccv3/user_test.go b/api/cloudcontroller/ccv3/user_test.go index 4331634e6d6..19637ae5b8e 100644 --- a/api/cloudcontroller/ccv3/user_test.go +++ b/api/cloudcontroller/ccv3/user_test.go @@ -1,9 +1,8 @@ package ccv3_test import ( - "net/http" - "fmt" + "net/http" "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" . "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" @@ -34,14 +33,14 @@ var _ = Describe("User", func() { When("no error occurs", func() { BeforeEach(func() { response := `{ - "guid": "some-uaa-guid", - "username": "some-user-name", - "presentation_name": "some-user-name", - "origin": "ldap", - "created_at": "2016-12-07T18:18:30Z", - "updated_at": null - - }` + "guid": "some-uaa-guid", + "username": "some-user-name", + "presentation_name": "some-user-name", + "origin": "ldap", + "created_at": "2016-12-07T18:18:30Z", + "updated_at": null + + }` expectedBody := `{"guid":"some-uaa-guid"}` server.AppendHandlers( CombineHandlers( @@ -355,4 +354,63 @@ var _ = Describe("User", func() { }) }) }) + + Describe("Who am I", func() { + var ( + k8sUser resources.K8sUser + warnings Warnings + executeErr error + ) + + JustBeforeEach(func() { + k8sUser, warnings, executeErr = client.WhoAmI() + }) + + When("the request succeeds", func() { + BeforeEach(func() { + response := `{ + "name": "bob", + "kind": "User" + }` + server.AppendHandlers( + CombineHandlers( + VerifyRequest(http.MethodGet, "/whoami"), + RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"warning-1"}}), + ), + ) + }) + + It("returns the expected user and all warnings", func() { + Expect(executeErr).ToNot(HaveOccurred()) + Expect(k8sUser.Name).To(Equal("bob")) + Expect(k8sUser.Kind).To(Equal("User")) + Expect(warnings).To(ConsistOf("warning-1")) + }) + }) + + When("cloud controller returns an error", func() { + BeforeEach(func() { + response := `{ + "errors": [ + { + "code": 1000, + "detail": "Not authenticated", + "title": "CF-InvalidAuthToken" + } + ] + }` + server.AppendHandlers( + CombineHandlers( + VerifyRequest(http.MethodGet, "/whoami"), + RespondWith(http.StatusUnauthorized, response, http.Header{"X-Cf-Warnings": {"warning-1"}}), + ), + ) + }) + + It("returns the error", func() { + Expect(executeErr).To(MatchError(ccerror.InvalidAuthTokenError{Message: "Not authenticated"})) + Expect(warnings).To(ConsistOf("warning-1")) + }) + }) + }) }) diff --git a/api/cloudcontroller/wrapper/kubernetes_authentication.go b/api/cloudcontroller/wrapper/kubernetes_authentication.go new file mode 100644 index 00000000000..b683278077e --- /dev/null +++ b/api/cloudcontroller/wrapper/kubernetes_authentication.go @@ -0,0 +1,151 @@ +package wrapper + +import ( + "bytes" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "net/http" + + "code.cloudfoundry.org/cli/actor/v7action" + "code.cloudfoundry.org/cli/api/cloudcontroller" + "code.cloudfoundry.org/cli/command" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/tools/clientcmd/api" + "k8s.io/client-go/transport" + + _ "k8s.io/client-go/plugin/pkg/client/auth/azure" + _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" + _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" +) + +type KubernetesAuthentication struct { + connection cloudcontroller.Connection + config command.Config + k8sConfigGetter v7action.KubernetesConfigGetter +} + +func NewKubernetesAuthentication( + config command.Config, + k8sConfigGetter v7action.KubernetesConfigGetter, +) *KubernetesAuthentication { + + return &KubernetesAuthentication{ + config: config, + k8sConfigGetter: k8sConfigGetter, + } +} + +func (a *KubernetesAuthentication) Make(request *cloudcontroller.Request, passedResponse *cloudcontroller.Response) error { + username, err := a.config.CurrentUserName() + if err != nil { + return err + } + if username == "" { + return errors.New("current user not set") + } + + k8sConfig, err := a.k8sConfigGetter.Get() + if err != nil { + return err + } + + restConfig, err := clientcmd.NewDefaultClientConfig( + *k8sConfig, + &clientcmd.ConfigOverrides{ + Context: api.Context{AuthInfo: username}, + }).ClientConfig() + if err != nil { + return err + } + + tlsConfig, err := rest.TLSConfigFor(restConfig) + if err != nil { + return fmt.Errorf("failed to get tls config: %w", err) + } + + if tlsConfig != nil && tlsConfig.GetClientCertificate != nil { + cert, err := tlsConfig.GetClientCertificate(nil) + if err != nil { + return fmt.Errorf("failed to get client certificate: %w", err) + } + + if len(cert.Certificate) > 0 && cert.PrivateKey != nil { + var buf bytes.Buffer + + if err := pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Certificate[0]}); err != nil { + return fmt.Errorf("could not convert certificate to PEM format: %w", err) + } + + key, err := x509.MarshalPKCS8PrivateKey(cert.PrivateKey) + if err != nil { + return fmt.Errorf("could not marshal private key: %w", err) + } + + if err := pem.Encode(&buf, &pem.Block{Type: "PRIVATE KEY", Bytes: key}); err != nil { + return fmt.Errorf("could not convert key to PEM format: %w", err) + } + + auth := "ClientCert " + base64.StdEncoding.EncodeToString(buf.Bytes()) + request.Header.Set("Authorization", auth) + + return a.connection.Make(request, passedResponse) + } + } + + transportConfig, err := restConfig.TransportConfig() + if err != nil { + return fmt.Errorf("failed to get transport config: %w", err) + } + + var roundtripper http.RoundTripper + if transportConfig.WrapTransport == nil { + // i.e. not auth-provider or exec plugin + roundtripper, err = transport.HTTPWrappersForConfig(transportConfig, connectionRoundTripper{ + connection: a.connection, + ccRequest: request, + ccResponse: passedResponse, + }) + if err != nil { + return fmt.Errorf("failed to create new transport: %w", err) + } + } else { + roundtripper = transportConfig.WrapTransport(connectionRoundTripper{ + connection: a.connection, + ccRequest: request, + ccResponse: passedResponse, + }) + } + + _, err = roundtripper.RoundTrip(request.Request) + + return err +} + +func (a *KubernetesAuthentication) Wrap(innerconnection cloudcontroller.Connection) cloudcontroller.Connection { + a.connection = innerconnection + + return a +} + +type connectionRoundTripper struct { + connection cloudcontroller.Connection + ccRequest *cloudcontroller.Request + ccResponse *cloudcontroller.Response +} + +func (rt connectionRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + // The passed `*req` is a shallow clone of the original `*req` with the auth header added. + // So we need to reset it on the `ccRequest`. + rt.ccRequest.Request = req + + err := rt.connection.Make(rt.ccRequest, rt.ccResponse) + if err != nil { + return nil, err + } + + return rt.ccResponse.HTTPResponse, nil +} diff --git a/api/cloudcontroller/wrapper/kubernetes_authentication_test.go b/api/cloudcontroller/wrapper/kubernetes_authentication_test.go new file mode 100644 index 00000000000..e46a282438e --- /dev/null +++ b/api/cloudcontroller/wrapper/kubernetes_authentication_test.go @@ -0,0 +1,460 @@ +package wrapper_test + +import ( + "encoding/base64" + "encoding/json" + "encoding/pem" + "errors" + "io/ioutil" + "net/http" + "os" + "strings" + "time" + + "code.cloudfoundry.org/cli/actor/v7action/v7actionfakes" + "code.cloudfoundry.org/cli/api/cloudcontroller" + "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/ccv3fakes" + "code.cloudfoundry.org/cli/api/cloudcontroller/wrapper" + "code.cloudfoundry.org/cli/command/commandfakes" + + "github.com/SermoDigital/jose/crypto" + "github.com/SermoDigital/jose/jws" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1" + "k8s.io/client-go/tools/clientcmd/api" +) + +const ( + clientCertData = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURJVENDQWdtZ0F3SUJBZ0lJVk9iMUFIckxNUjh3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TVRFd01EVXhOVEExTURsYUZ3MHlNakV3TURVeE5UQTFNVEZhTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXJrdWxLbS9qTTJhZWZsdjkKK00zQk9Jc2QvVXZrRTBONGhWb3hSeWRBbE0xQXhWd3REYUdzL3dmUzRzb0xuNHJENTF3UE1SRlNJaitwSzdGYQprRGdaR0x4UFhrai96UkZOTzcvU3J2RHYwVGxjYjJENzNCS21qaXArQ2hBWkpQdWhMQlY2VnlTN0pXSWhOM1lOCktyamR5TnB5MHN3SjI1TW9CbW1saUpFc3V2dCtDaEhseERqWE9KenF1U2owa1hPQVVsWUFTN1dKK09JMU9HbzQKUjcvdHdHZlFTNW9oYXpRVVlDR2lZSllYcjVRNkVKTmJOVVI0RjdpRSthY1I5Rm9GNnNKSmkrQStET1VDUFFSKwptbjQ5Zm1pcFVHSGtMc3BicTNFZ0FEME40VW5jcmIyeUJEMFNVTmdLQmJjclY1S2hybFA2SzkwNkY5NEpubzNHCm1Id1JwUUlEQVFBQm8xWXdWREFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RBWURWUjBUQVFIL0JBSXdBREFmQmdOVkhTTUVHREFXZ0JUV2VNZ1ZBRkRhbWcraDRqS3hoRUh2Q1l5egp5akFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBUUxMWWFXQTRva1M2b3ZEWjQ1Z28ybkVZdUR4MklmRXZwYnh3CkNmYkFTNDY4M3lLT3FiYVBHOEpTVGhSbkh3TWlMcVBrbGFsdkJvV2R3aFB5Vkk0d2tVNHI4Y2c0UEpxNEZwWnQKVkNUQzFPZWVwRGpTMFpVQjRwSDVIZVlNQUxqSDBqcFV3RU96djFpaEtid05IMHFoZ2pGeUNTdld5TG9oZHdzbApJWXIvV1NEZm50NlBETC84TjFpcEJJbEN5Z1JHVGdoSFhPemhHUklPWG4rYWVOR29yWm9YWm0xbHErc1hyUnc5CktNdVZhRmdhaWVjSm0vbytyemFFSG9VZjRYOERKeVNubmVTa3ViaEx6ZERNc2o5eEs1cEJpdFgvaDlQMUQrMkcKeW5rcWdJVTJSWTM0SjBRcnU4Z0syNlJVT2pOcHIvRWJHQ0dUQUxiMXJnSDM0K2NFdlE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" + clientKeyData = "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2Z0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktnd2dnU2tBZ0VBQW9JQkFRQ3VTNlVxYitNelpwNSsKVy8zNHpjRTRpeDM5UytRVFEzaUZXakZISjBDVXpVREZYQzBOb2F6L0I5TGl5Z3VmaXNQblhBOHhFVklpUDZrcgpzVnFRT0JrWXZFOWVTUC9ORVUwN3Y5S3U4Ty9ST1Z4dllQdmNFcWFPS240S0VCa2srNkVzRlhwWEpMc2xZaUUzCmRnMHF1TjNJMm5MU3pBbmJreWdHYWFXSWtTeTYrMzRLRWVYRU9OYzRuT3E1S1BTUmM0QlNWZ0JMdFluNDRqVTQKYWpoSHYrM0FaOUJMbWlGck5CUmdJYUpnbGhldmxEb1FrMXMxUkhnWHVJVDVweEgwV2dYcXdrbUw0RDRNNVFJOQpCSDZhZmoxK2FLbFFZZVF1eWx1cmNTQUFQUTNoU2R5dHZiSUVQUkpRMkFvRnR5dFhrcUd1VS9vcjNUb1gzZ21lCmpjYVlmQkdsQWdNQkFBRUNnZ0VBZG80WndLM3VteTM0TFBjaDM3VUU4eE1keVFkd0VmSlk3a3dWTE5MMFNNTDgKaGNKWEd1aVlKYmtLcHh6TG55L2laV0xuS25jZnFSQW9ZQUg1R2hRdWJmYlkvY2NseURVMmxhZTdCU2Y1MkJUdQpYUXhaQks3aS85ekRjdERVYWFXSFVkY2lLbGhmdStQdHVDM2ljdWJnWlJqQjljUzRCOVVtNm9XK0JSREtuandICkduQ0lEZlNNQWt4VXdTaUwwa2NXelNpZ1BYMVN3UHcxOEZvZWgzTmJEd1VXTHhxUWZLVThydVlSTUsxYUg5M3cKcjFtbjlDWUwvd0hiVWRqcmtZMlIxTjVUR21ab2Vldm5qUXgyQVc2NkYzdEg1cGg4RTF6TEFQVTl4TFdRTW9KcwpXM0gzSTdUaEYvRnJuNERQa3hQbThUUVVhQUdvQ09SSWFUQkN5VlgxQVFLQmdRREkxbkRmNWYySHdHaldrTStpCk9YbGE1R1VnRUtXaGZpeGhidE5OclNpMDU5VnZQUEJwNXdtbGQzMHJKUDhWem8vbnFnUW5ISmpmaEQ2Y3NSMTQKL2VlMHZ1Um0zYzZwZzMrODdwOHhWY3lLNHhDd0JmdFFuMGRZWWFLMkRMOEtYb0liYThpN09EQmFoNW5OZWQwcgpKa1RPcE5NRGRkL0p0bEpPZ25jRXBlUk9oUUtCZ1FEZUt1L0R1MXU1QVR3Y3p5STRXOWV1L1YwTXRwMHdqM3RpClF2MmpObW83QU1zS3BwK0ZKVDFqWFhUKzZCTm02OWpxUVJwdlAyd2RhVUdqV1dLa1lHVEVpbUZCc2ZuKzJDOFAKOEc3Uk50YWpRdEV2QlR1ZDZPN0tZUkFoTU56dm9RcDkrZmJKY1ZsRG13Nlk0bUYzUTJXS3NmZU51TGtpY3VqNQpYVFV1ekVMd29RS0JnUUREU0IvQTFYVEx4cjhwd3V6aHBGam5sQ1R3Skwrb1kzTHIya01EeUZkSWNCUU1jWWlpCnNNK2tZS2NJaUpTdnM0WWhrQ014bEpEZzVVbXNPbHVhQmVpQ3l3cHpLMEdEZWlWK285ZU90UXFLRVhkc2NLU0oKSkJiUFRVQlZHOWUyVVdiWkd0aTNrazhSOThBSkYzR0NQMWV3Um53WFpVb1FiSU5qYTJBbTJOZEJzUUtCZ0Q4eApOVXVXTWl1NE56SDJsTVExRTI4NXI4cmE4bkVLanN6UFF6ZTJWWmI4emNQMHl2RGpPOGZVb0YrVkFWZklBOFgxCnlLQVdDUm1BZytRRG03UW5tdUh3Zm1OaVRUcDRvVUpHWUM3d0N6TWE0VWNmbE9xQWc5TmFzbXpPYWpsYXRCSkwKRkRBT0pwYTlOdlN6aDRlVnl2OGRTYzJzMmpQN1BWc1ljUFVqc25LaEFvR0JBSy9kQjlnVEFpME5nczVmaVNtWQovWkp3Yk52MjcyTHdKbWV4Vit2eWtjN3J5LzRraTRQb2xRd1BHNzQ5eFZ0T2NNc2FhRlVNMVVkclN2NlIwbjlkCmpTbXhCeTl2YWdzc1FmVDNSc3BvUUJKM0w5YWxiNHM2V2ZtUEpzNkFrQkhIZHNpVXFaaElYT2J2WE1lQ0k2aVMKOTQ2R0toekFxMlVGbjhFUGxXaFVNeEFiCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K" +) + +var _ = Describe("KubernetesAuthentication", func() { + var ( + k8sAuthWrapper *wrapper.KubernetesAuthentication + config *commandfakes.FakeConfig + k8sConfigGetter *v7actionfakes.FakeKubernetesConfigGetter + wrappedConnection *ccv3fakes.FakeConnectionWrapper + req *cloudcontroller.Request + resp *cloudcontroller.Response + kubeConfig *api.Config + makeErr error + ) + + BeforeEach(func() { + kubeConfig = &api.Config{ + Kind: "Config", + APIVersion: "v1", + Clusters: map[string]*api.Cluster{ + "my-cluster": { + Server: "https://example.org", + }, + }, + Contexts: map[string]*api.Context{ + "my-context": { + Cluster: "my-cluster", + AuthInfo: "my-auth-info", + Namespace: "my-namespace", + }, + }, + CurrentContext: "my-context", + AuthInfos: map[string]*api.AuthInfo{}, + } + + k8sConfigGetter = new(v7actionfakes.FakeKubernetesConfigGetter) + k8sConfigGetter.GetReturns(kubeConfig, nil) + + config = new(commandfakes.FakeConfig) + config.CurrentUserNameReturns("auth-test", nil) + + wrappedConnection = new(ccv3fakes.FakeConnectionWrapper) + + httpReq, err := http.NewRequest(http.MethodPost, "", strings.NewReader("hello")) + Expect(err).NotTo(HaveOccurred()) + req = cloudcontroller.NewRequest(httpReq, nil) + + resp = &cloudcontroller.Response{ + HTTPResponse: &http.Response{ + StatusCode: http.StatusTeapot, + }, + } + }) + + JustBeforeEach(func() { + k8sAuthWrapper = wrapper.NewKubernetesAuthentication(config, k8sConfigGetter) + k8sAuthWrapper.Wrap(wrappedConnection) + + makeErr = k8sAuthWrapper.Make(req, resp) + }) + + When("getting the k8s config fails", func() { + BeforeEach(func() { + k8sConfigGetter.GetReturns(nil, errors.New("boom!")) + }) + + It("returns the error", func() { + Expect(makeErr).To(MatchError("boom!")) + }) + }) + + When("no user is set in the config", func() { + BeforeEach(func() { + config.CurrentUserNameReturns("", nil) + }) + + It("errors", func() { + Expect(makeErr).To(MatchError(ContainSubstring("current user not set"))) + }) + }) + + When("there is an error getting the current user from the config", func() { + BeforeEach(func() { + config.CurrentUserNameReturns("", errors.New("boom")) + }) + + It("errors", func() { + Expect(makeErr).To(MatchError(ContainSubstring("boom"))) + }) + }) + + When("the chosen kubeernetes auth info is not present in kubeconfig", func() { + BeforeEach(func() { + config.CurrentUserNameReturns("not-present", nil) + }) + + It("errors", func() { + Expect(makeErr).To(MatchError(ContainSubstring(`auth info "not-present" does not exist`))) + }) + }) + + checkCalls := func() *cloudcontroller.Request { + Expect(makeErr).NotTo(HaveOccurred()) + Expect(wrappedConnection.MakeCallCount()).To(Equal(1)) + + actualReq, actualResp := wrappedConnection.MakeArgsForCall(0) + Expect(actualResp.HTTPResponse).To(HaveHTTPStatus(http.StatusTeapot)) + + body, err := ioutil.ReadAll(actualReq.Body) + Expect(err).NotTo(HaveOccurred()) + Expect(string(body)).To(Equal("hello")) + + return actualReq + } + + checkBearerTokenInAuthHeader := func() { + actualReq := checkCalls() + + token, err := jws.ParseJWTFromRequest(actualReq.Request) + Expect(err).NotTo(HaveOccurred()) + Expect(token.Validate(keyPair.Public(), crypto.SigningMethodRS256)).To(Succeed()) + + claims := token.Claims() + Expect(claims).To(HaveKeyWithValue("another", "thing")) + } + + checkClientCertInAuthHeader := func() { + actualReq := checkCalls() + + Expect(actualReq.Header).To(HaveKeyWithValue("Authorization", ConsistOf(HavePrefix("ClientCert ")))) + + certAndKeyPEMBase64 := actualReq.Header.Get("Authorization")[11:] + certAndKeyPEM, err := base64.StdEncoding.DecodeString(certAndKeyPEMBase64) + Expect(err).NotTo(HaveOccurred()) + + cert, rest := pem.Decode(certAndKeyPEM) + Expect(cert.Type).To(Equal(pemDecodeKubeConfigCertData(clientCertData).Type)) + Expect(cert.Bytes).To(Equal(pemDecodeKubeConfigCertData(clientCertData).Bytes)) + + var key *pem.Block + key, rest = pem.Decode(rest) + Expect(key.Bytes).To(Equal(pemDecodeKubeConfigCertData(clientKeyData).Bytes)) + + Expect(rest).To(BeEmpty()) + } + + Describe("auth-provider", func() { + var token []byte + + BeforeEach(func() { + jwt := jws.NewJWT(jws.Claims{ + "exp": time.Now().Add(time.Hour).Unix(), + "another": "thing", + }, crypto.SigningMethodRS256) + var err error + token, err = jwt.Serialize(keyPair) + Expect(err).NotTo(HaveOccurred()) + + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + AuthProvider: &api.AuthProviderConfig{ + Name: "oidc", + Config: map[string]string{ + "id-token": string(token), + "idp-issuer-url": "-", + "client-id": "-", + }, + }, + } + }) + + It("uses the auth-provider to generate the Bearer token", func() { + checkBearerTokenInAuthHeader() + }) + }) + + Describe("client certs", func() { + var ( + certFilePath string + keyFilePath string + ) + + BeforeEach(func() { + certFilePath = writeToFile(clientCertData) + keyFilePath = writeToFile(clientKeyData) + }) + + AfterEach(func() { + Expect(os.RemoveAll(certFilePath)).To(Succeed()) + Expect(os.RemoveAll(keyFilePath)).To(Succeed()) + }) + + When("inline cert and key are provided", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + ClientCertificateData: []byte(base64Decode(clientCertData)), + ClientKeyData: []byte(base64Decode(clientKeyData)), + } + }) + + It("puts concatenated client ceritificate and key data into the Authorization header", func() { + checkClientCertInAuthHeader() + }) + }) + + When("cert and key are provided in files", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + ClientCertificate: certFilePath, + ClientKey: keyFilePath, + } + }) + + It("puts concatenated client ceritificate and key data into the Authorization header", func() { + checkClientCertInAuthHeader() + }) + + When("cert file cannot be read", func() { + BeforeEach(func() { + Expect(os.Remove(certFilePath)).To(Succeed()) + }) + + It("returns an error", func() { + Expect(makeErr).To(MatchError(ContainSubstring(certFilePath))) + }) + }) + + When("key file cannot be read", func() { + BeforeEach(func() { + Expect(os.Remove(keyFilePath)).To(Succeed()) + }) + + It("returns an error", func() { + Expect(makeErr).To(MatchError(ContainSubstring(keyFilePath))) + }) + }) + }) + + When("file and inline cert is provided", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + ClientCertificate: certFilePath, + ClientCertificateData: []byte(base64Decode(clientCertData)), + ClientKeyData: []byte(base64Decode(clientKeyData)), + } + }) + + It("complains about invalid configuration", func() { + Expect(makeErr).To(MatchError(ContainSubstring("client-cert-data and client-cert are both specified"))) + }) + }) + + When("file and inline key is provided", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + ClientCertificateData: []byte(base64Decode(clientCertData)), + ClientKeyData: []byte(base64Decode(clientKeyData)), + ClientKey: keyFilePath, + } + }) + + It("complains about invalid configuration", func() { + Expect(makeErr).To(MatchError(ContainSubstring("client-key-data and client-key are both specified"))) + }) + }) + + When("inline cert and key file are provided", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + ClientCertificateData: []byte(base64Decode(clientCertData)), + ClientKey: keyFilePath, + } + }) + + It("uses the inline key", func() { + checkClientCertInAuthHeader() + }) + }) + + When("cert file and inline key are provided", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + ClientCertificate: certFilePath, + ClientKeyData: []byte(base64Decode(clientKeyData)), + } + }) + + It("uses the inline key", func() { + checkClientCertInAuthHeader() + }) + }) + }) + + Describe("exec", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + Exec: &api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1beta1", + InteractiveMode: "Never", + Command: "echo", + }, + } + }) + + When("the command returns a token", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"].Exec.Args = []string{execCredential(&clientauthenticationv1beta1.ExecCredentialStatus{ + Token: "a-token", + })} + }) + + It("uses the exec command to generate the Bearer token", func() { + Expect(makeErr).NotTo(HaveOccurred()) + Expect(wrappedConnection.MakeCallCount()).To(Equal(1)) + + actualReq, actualResp := wrappedConnection.MakeArgsForCall(0) + Expect(actualResp.HTTPResponse).To(HaveHTTPStatus(http.StatusTeapot)) + Expect(actualReq.Header.Get("Authorization")).To(Equal("Bearer a-token")) + }) + }) + + When("the command returns a client cert and key", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"].Exec.Args = []string{execCredential(&clientauthenticationv1beta1.ExecCredentialStatus{ + ClientCertificateData: base64Decode(clientCertData), + ClientKeyData: base64Decode(clientKeyData), + })} + }) + + It("uses the exec command to generate client certs", func() { + checkClientCertInAuthHeader() + }) + }) + }) + + Describe("tokens provided in config", func() { + var token []byte + + BeforeEach(func() { + jwt := jws.NewJWT(jws.Claims{ + "exp": time.Now().Add(time.Hour).Unix(), + "another": "thing", + }, crypto.SigningMethodRS256) + var err error + token, err = jwt.Serialize(keyPair) + Expect(err).NotTo(HaveOccurred()) + }) + + Context("inline tokens", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + Token: string(token), + } + }) + + It("inserts the token in the authorization header", func() { + checkBearerTokenInAuthHeader() + }) + }) + + Context("token file paths", func() { + var tokenFilePath string + + BeforeEach(func() { + tokenFile, err := ioutil.TempFile("", "") + Expect(err).NotTo(HaveOccurred()) + defer tokenFile.Close() + _, err = tokenFile.Write(token) + Expect(err).NotTo(HaveOccurred()) + tokenFilePath = tokenFile.Name() + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + TokenFile: tokenFilePath, + } + }) + + AfterEach(func() { + Expect(os.RemoveAll(tokenFilePath)).To(Succeed()) + }) + + It("inserts the token in the authorization header", func() { + checkBearerTokenInAuthHeader() + }) + }) + + When("both file and inline token are provided", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + Token: string(token), + TokenFile: "some-path", + } + }) + + It("the inline token takes precedence", func() { + checkBearerTokenInAuthHeader() + }) + }) + }) +}) + +func pemDecodeKubeConfigCertData(data string) *pem.Block { + decodedData, err := base64.StdEncoding.DecodeString(data) + Expect(err).NotTo(HaveOccurred()) + pemDecodedBlock, rest := pem.Decode(decodedData) + Expect(rest).To(BeEmpty()) + return pemDecodedBlock +} + +func base64Decode(encoded string) string { + decoded, err := base64.StdEncoding.DecodeString(encoded) + Expect(err).NotTo(HaveOccurred()) + return string(decoded) +} + +func writeToFile(base64Data string) string { + file, err := ioutil.TempFile("", "") + Expect(err).NotTo(HaveOccurred()) + file.WriteString(base64Decode(base64Data)) + Expect(file.Close()).To(Succeed()) + return file.Name() +} + +func execCredential(status *clientauthenticationv1beta1.ExecCredentialStatus) string { + execCred, err := json.Marshal(clientauthenticationv1beta1.ExecCredential{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "client.authentication.k8s.io/v1beta1", + }, + Status: status, + }) + Expect(err).NotTo(HaveOccurred()) + return string(execCred) +} diff --git a/api/cloudcontroller/wrapper/uaa_authentication.go b/api/cloudcontroller/wrapper/uaa_authentication.go index 861f5b4e9d7..d11ae162857 100644 --- a/api/cloudcontroller/wrapper/uaa_authentication.go +++ b/api/cloudcontroller/wrapper/uaa_authentication.go @@ -50,10 +50,6 @@ func NewUAAAuthentication(client UAAClient, cache TokenCache) *UAAAuthentication // wrapped connection's Make. If the client is not set on the wrapper, it will // not add any header or handle any authentication errors. func (t *UAAAuthentication) Make(request *cloudcontroller.Request, passedResponse *cloudcontroller.Response) error { - if t.client == nil { - return t.connection.Make(request, passedResponse) - } - if request.Header.Get("Authorization") == "" && (t.cache.AccessToken() != "" || t.cache.RefreshToken() != "") { // assert a valid access token for authenticated requests err := t.refreshTokenIfNecessary(t.cache.AccessToken()) diff --git a/api/cloudcontroller/wrapper/uaa_authentication_test.go b/api/cloudcontroller/wrapper/uaa_authentication_test.go index b89f219dc93..e6429356230 100644 --- a/api/cloudcontroller/wrapper/uaa_authentication_test.go +++ b/api/cloudcontroller/wrapper/uaa_authentication_test.go @@ -50,22 +50,6 @@ var _ = Describe("UAA Authentication", func() { }) Describe("Make", func() { - When("the client is nil", func() { - BeforeEach(func() { - inner.SetClient(nil) - - fakeConnection.MakeReturns(ccerror.InvalidAuthTokenError{}) - }) - - It("calls the connection without any side effects", func() { - err := wrapper.Make(request, nil) - Expect(err).To(MatchError(ccerror.InvalidAuthTokenError{})) - - Expect(fakeClient.RefreshAccessTokenCallCount()).To(Equal(0)) - Expect(fakeConnection.MakeCallCount()).To(Equal(1)) - }) - }) - When("no tokens are set", func() { BeforeEach(func() { inMemoryCache.SetAccessToken("") diff --git a/api/cloudcontroller/wrapper/wrapper_suite_test.go b/api/cloudcontroller/wrapper/wrapper_suite_test.go index f0ca6eeda02..ba828571f05 100644 --- a/api/cloudcontroller/wrapper/wrapper_suite_test.go +++ b/api/cloudcontroller/wrapper/wrapper_suite_test.go @@ -2,13 +2,14 @@ package wrapper_test import ( "bytes" + "crypto/rand" + "crypto/rsa" "log" + "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/ghttp" - - "testing" ) func TestCloudcontroller(t *testing.T) { @@ -16,7 +17,10 @@ func TestCloudcontroller(t *testing.T) { RunSpecs(t, "Cloud Controller Wrapper Suite") } -var server *Server +var ( + server *Server + keyPair *rsa.PrivateKey +) var _ = SynchronizedBeforeSuite(func() []byte { return []byte{} @@ -25,6 +29,10 @@ var _ = SynchronizedBeforeSuite(func() []byte { // Suppresses ginkgo server logs server.HTTPTestServer.Config.ErrorLog = log.New(&bytes.Buffer{}, "", 0) + + var err error + keyPair, err = rsa.GenerateKey(rand.Reader, 2048) + Expect(err).NotTo(HaveOccurred()) }) var _ = SynchronizedAfterSuite(func() { diff --git a/cf/configuration/coreconfig/config_data.go b/cf/configuration/coreconfig/config_data.go index 975d1aa0ee7..a5314a124c4 100644 --- a/cf/configuration/coreconfig/config_data.go +++ b/cf/configuration/coreconfig/config_data.go @@ -12,11 +12,13 @@ type AuthPromptType string const ( AuthPromptTypeText AuthPromptType = "TEXT" AuthPromptTypePassword AuthPromptType = "PASSWORD" + AuthPromptTypeMenu AuthPromptType = "MENU" ) type AuthPrompt struct { Type AuthPromptType DisplayName string + Entries []string } type Data struct { diff --git a/command/commandfakes/fake_config.go b/command/commandfakes/fake_config.go index 4a4c307d06e..4e94d9f543c 100644 --- a/command/commandfakes/fake_config.go +++ b/command/commandfakes/fake_config.go @@ -201,6 +201,16 @@ type FakeConfig struct { hasTargetedSpaceReturnsOnCall map[int]struct { result1 bool } + IsCFOnK8sStub func() bool + isCFOnK8sMutex sync.RWMutex + isCFOnK8sArgsForCall []struct { + } + isCFOnK8sReturns struct { + result1 bool + } + isCFOnK8sReturnsOnCall map[int]struct { + result1 bool + } IsTTYStub func() bool isTTYMutex sync.RWMutex isTTYArgsForCall []struct { @@ -371,6 +381,11 @@ type FakeConfig struct { setColorEnabledArgsForCall []struct { arg1 string } + SetKubernetesAuthInfoStub func(string) + setKubernetesAuthInfoMutex sync.RWMutex + setKubernetesAuthInfoArgsForCall []struct { + arg1 string + } SetLocaleStub func(string) setLocaleMutex sync.RWMutex setLocaleArgsForCall []struct { @@ -621,16 +636,15 @@ func (fake *FakeConfig) APIVersion() string { ret, specificReturn := fake.aPIVersionReturnsOnCall[len(fake.aPIVersionArgsForCall)] fake.aPIVersionArgsForCall = append(fake.aPIVersionArgsForCall, struct { }{}) - stub := fake.APIVersionStub - fakeReturns := fake.aPIVersionReturns fake.recordInvocation("APIVersion", []interface{}{}) fake.aPIVersionMutex.Unlock() - if stub != nil { - return stub() + if fake.APIVersionStub != nil { + return fake.APIVersionStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.aPIVersionReturns return fakeReturns.result1 } @@ -674,16 +688,15 @@ func (fake *FakeConfig) AccessToken() string { ret, specificReturn := fake.accessTokenReturnsOnCall[len(fake.accessTokenArgsForCall)] fake.accessTokenArgsForCall = append(fake.accessTokenArgsForCall, struct { }{}) - stub := fake.AccessTokenStub - fakeReturns := fake.accessTokenReturns fake.recordInvocation("AccessToken", []interface{}{}) fake.accessTokenMutex.Unlock() - if stub != nil { - return stub() + if fake.AccessTokenStub != nil { + return fake.AccessTokenStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.accessTokenReturns return fakeReturns.result1 } @@ -727,10 +740,9 @@ func (fake *FakeConfig) AddPlugin(arg1 configv3.Plugin) { fake.addPluginArgsForCall = append(fake.addPluginArgsForCall, struct { arg1 configv3.Plugin }{arg1}) - stub := fake.AddPluginStub fake.recordInvocation("AddPlugin", []interface{}{arg1}) fake.addPluginMutex.Unlock() - if stub != nil { + if fake.AddPluginStub != nil { fake.AddPluginStub(arg1) } } @@ -760,10 +772,9 @@ func (fake *FakeConfig) AddPluginRepository(arg1 string, arg2 string) { arg1 string arg2 string }{arg1, arg2}) - stub := fake.AddPluginRepositoryStub fake.recordInvocation("AddPluginRepository", []interface{}{arg1, arg2}) fake.addPluginRepositoryMutex.Unlock() - if stub != nil { + if fake.AddPluginRepositoryStub != nil { fake.AddPluginRepositoryStub(arg1, arg2) } } @@ -792,16 +803,15 @@ func (fake *FakeConfig) AuthorizationEndpoint() string { ret, specificReturn := fake.authorizationEndpointReturnsOnCall[len(fake.authorizationEndpointArgsForCall)] fake.authorizationEndpointArgsForCall = append(fake.authorizationEndpointArgsForCall, struct { }{}) - stub := fake.AuthorizationEndpointStub - fakeReturns := fake.authorizationEndpointReturns fake.recordInvocation("AuthorizationEndpoint", []interface{}{}) fake.authorizationEndpointMutex.Unlock() - if stub != nil { - return stub() + if fake.AuthorizationEndpointStub != nil { + return fake.AuthorizationEndpointStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.authorizationEndpointReturns return fakeReturns.result1 } @@ -845,16 +855,15 @@ func (fake *FakeConfig) BinaryName() string { ret, specificReturn := fake.binaryNameReturnsOnCall[len(fake.binaryNameArgsForCall)] fake.binaryNameArgsForCall = append(fake.binaryNameArgsForCall, struct { }{}) - stub := fake.BinaryNameStub - fakeReturns := fake.binaryNameReturns fake.recordInvocation("BinaryName", []interface{}{}) fake.binaryNameMutex.Unlock() - if stub != nil { - return stub() + if fake.BinaryNameStub != nil { + return fake.BinaryNameStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.binaryNameReturns return fakeReturns.result1 } @@ -898,16 +907,15 @@ func (fake *FakeConfig) BinaryVersion() string { ret, specificReturn := fake.binaryVersionReturnsOnCall[len(fake.binaryVersionArgsForCall)] fake.binaryVersionArgsForCall = append(fake.binaryVersionArgsForCall, struct { }{}) - stub := fake.BinaryVersionStub - fakeReturns := fake.binaryVersionReturns fake.recordInvocation("BinaryVersion", []interface{}{}) fake.binaryVersionMutex.Unlock() - if stub != nil { - return stub() + if fake.BinaryVersionStub != nil { + return fake.BinaryVersionStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.binaryVersionReturns return fakeReturns.result1 } @@ -951,16 +959,15 @@ func (fake *FakeConfig) CFPassword() string { ret, specificReturn := fake.cFPasswordReturnsOnCall[len(fake.cFPasswordArgsForCall)] fake.cFPasswordArgsForCall = append(fake.cFPasswordArgsForCall, struct { }{}) - stub := fake.CFPasswordStub - fakeReturns := fake.cFPasswordReturns fake.recordInvocation("CFPassword", []interface{}{}) fake.cFPasswordMutex.Unlock() - if stub != nil { - return stub() + if fake.CFPasswordStub != nil { + return fake.CFPasswordStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.cFPasswordReturns return fakeReturns.result1 } @@ -1004,16 +1011,15 @@ func (fake *FakeConfig) CFUsername() string { ret, specificReturn := fake.cFUsernameReturnsOnCall[len(fake.cFUsernameArgsForCall)] fake.cFUsernameArgsForCall = append(fake.cFUsernameArgsForCall, struct { }{}) - stub := fake.CFUsernameStub - fakeReturns := fake.cFUsernameReturns fake.recordInvocation("CFUsername", []interface{}{}) fake.cFUsernameMutex.Unlock() - if stub != nil { - return stub() + if fake.CFUsernameStub != nil { + return fake.CFUsernameStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.cFUsernameReturns return fakeReturns.result1 } @@ -1057,16 +1063,15 @@ func (fake *FakeConfig) ColorEnabled() configv3.ColorSetting { ret, specificReturn := fake.colorEnabledReturnsOnCall[len(fake.colorEnabledArgsForCall)] fake.colorEnabledArgsForCall = append(fake.colorEnabledArgsForCall, struct { }{}) - stub := fake.ColorEnabledStub - fakeReturns := fake.colorEnabledReturns fake.recordInvocation("ColorEnabled", []interface{}{}) fake.colorEnabledMutex.Unlock() - if stub != nil { - return stub() + if fake.ColorEnabledStub != nil { + return fake.ColorEnabledStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.colorEnabledReturns return fakeReturns.result1 } @@ -1110,16 +1115,15 @@ func (fake *FakeConfig) CurrentUser() (configv3.User, error) { ret, specificReturn := fake.currentUserReturnsOnCall[len(fake.currentUserArgsForCall)] fake.currentUserArgsForCall = append(fake.currentUserArgsForCall, struct { }{}) - stub := fake.CurrentUserStub - fakeReturns := fake.currentUserReturns fake.recordInvocation("CurrentUser", []interface{}{}) fake.currentUserMutex.Unlock() - if stub != nil { - return stub() + if fake.CurrentUserStub != nil { + return fake.CurrentUserStub() } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.currentUserReturns return fakeReturns.result1, fakeReturns.result2 } @@ -1166,16 +1170,15 @@ func (fake *FakeConfig) CurrentUserName() (string, error) { ret, specificReturn := fake.currentUserNameReturnsOnCall[len(fake.currentUserNameArgsForCall)] fake.currentUserNameArgsForCall = append(fake.currentUserNameArgsForCall, struct { }{}) - stub := fake.CurrentUserNameStub - fakeReturns := fake.currentUserNameReturns fake.recordInvocation("CurrentUserName", []interface{}{}) fake.currentUserNameMutex.Unlock() - if stub != nil { - return stub() + if fake.CurrentUserNameStub != nil { + return fake.CurrentUserNameStub() } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.currentUserNameReturns return fakeReturns.result1, fakeReturns.result2 } @@ -1222,16 +1225,15 @@ func (fake *FakeConfig) DialTimeout() time.Duration { ret, specificReturn := fake.dialTimeoutReturnsOnCall[len(fake.dialTimeoutArgsForCall)] fake.dialTimeoutArgsForCall = append(fake.dialTimeoutArgsForCall, struct { }{}) - stub := fake.DialTimeoutStub - fakeReturns := fake.dialTimeoutReturns fake.recordInvocation("DialTimeout", []interface{}{}) fake.dialTimeoutMutex.Unlock() - if stub != nil { - return stub() + if fake.DialTimeoutStub != nil { + return fake.DialTimeoutStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.dialTimeoutReturns return fakeReturns.result1 } @@ -1275,16 +1277,15 @@ func (fake *FakeConfig) DockerPassword() string { ret, specificReturn := fake.dockerPasswordReturnsOnCall[len(fake.dockerPasswordArgsForCall)] fake.dockerPasswordArgsForCall = append(fake.dockerPasswordArgsForCall, struct { }{}) - stub := fake.DockerPasswordStub - fakeReturns := fake.dockerPasswordReturns fake.recordInvocation("DockerPassword", []interface{}{}) fake.dockerPasswordMutex.Unlock() - if stub != nil { - return stub() + if fake.DockerPasswordStub != nil { + return fake.DockerPasswordStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.dockerPasswordReturns return fakeReturns.result1 } @@ -1328,16 +1329,15 @@ func (fake *FakeConfig) Experimental() bool { ret, specificReturn := fake.experimentalReturnsOnCall[len(fake.experimentalArgsForCall)] fake.experimentalArgsForCall = append(fake.experimentalArgsForCall, struct { }{}) - stub := fake.ExperimentalStub - fakeReturns := fake.experimentalReturns fake.recordInvocation("Experimental", []interface{}{}) fake.experimentalMutex.Unlock() - if stub != nil { - return stub() + if fake.ExperimentalStub != nil { + return fake.ExperimentalStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.experimentalReturns return fakeReturns.result1 } @@ -1382,16 +1382,15 @@ func (fake *FakeConfig) GetPlugin(arg1 string) (configv3.Plugin, bool) { fake.getPluginArgsForCall = append(fake.getPluginArgsForCall, struct { arg1 string }{arg1}) - stub := fake.GetPluginStub - fakeReturns := fake.getPluginReturns fake.recordInvocation("GetPlugin", []interface{}{arg1}) fake.getPluginMutex.Unlock() - if stub != nil { - return stub(arg1) + if fake.GetPluginStub != nil { + return fake.GetPluginStub(arg1) } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.getPluginReturns return fakeReturns.result1, fakeReturns.result2 } @@ -1446,16 +1445,15 @@ func (fake *FakeConfig) GetPluginCaseInsensitive(arg1 string) (configv3.Plugin, fake.getPluginCaseInsensitiveArgsForCall = append(fake.getPluginCaseInsensitiveArgsForCall, struct { arg1 string }{arg1}) - stub := fake.GetPluginCaseInsensitiveStub - fakeReturns := fake.getPluginCaseInsensitiveReturns fake.recordInvocation("GetPluginCaseInsensitive", []interface{}{arg1}) fake.getPluginCaseInsensitiveMutex.Unlock() - if stub != nil { - return stub(arg1) + if fake.GetPluginCaseInsensitiveStub != nil { + return fake.GetPluginCaseInsensitiveStub(arg1) } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.getPluginCaseInsensitiveReturns return fakeReturns.result1, fakeReturns.result2 } @@ -1509,16 +1507,15 @@ func (fake *FakeConfig) HasTargetedOrganization() bool { ret, specificReturn := fake.hasTargetedOrganizationReturnsOnCall[len(fake.hasTargetedOrganizationArgsForCall)] fake.hasTargetedOrganizationArgsForCall = append(fake.hasTargetedOrganizationArgsForCall, struct { }{}) - stub := fake.HasTargetedOrganizationStub - fakeReturns := fake.hasTargetedOrganizationReturns fake.recordInvocation("HasTargetedOrganization", []interface{}{}) fake.hasTargetedOrganizationMutex.Unlock() - if stub != nil { - return stub() + if fake.HasTargetedOrganizationStub != nil { + return fake.HasTargetedOrganizationStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.hasTargetedOrganizationReturns return fakeReturns.result1 } @@ -1562,16 +1559,15 @@ func (fake *FakeConfig) HasTargetedSpace() bool { ret, specificReturn := fake.hasTargetedSpaceReturnsOnCall[len(fake.hasTargetedSpaceArgsForCall)] fake.hasTargetedSpaceArgsForCall = append(fake.hasTargetedSpaceArgsForCall, struct { }{}) - stub := fake.HasTargetedSpaceStub - fakeReturns := fake.hasTargetedSpaceReturns fake.recordInvocation("HasTargetedSpace", []interface{}{}) fake.hasTargetedSpaceMutex.Unlock() - if stub != nil { - return stub() + if fake.HasTargetedSpaceStub != nil { + return fake.HasTargetedSpaceStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.hasTargetedSpaceReturns return fakeReturns.result1 } @@ -1610,21 +1606,72 @@ func (fake *FakeConfig) HasTargetedSpaceReturnsOnCall(i int, result1 bool) { }{result1} } +func (fake *FakeConfig) IsCFOnK8s() bool { + fake.isCFOnK8sMutex.Lock() + ret, specificReturn := fake.isCFOnK8sReturnsOnCall[len(fake.isCFOnK8sArgsForCall)] + fake.isCFOnK8sArgsForCall = append(fake.isCFOnK8sArgsForCall, struct { + }{}) + fake.recordInvocation("IsCFOnK8s", []interface{}{}) + fake.isCFOnK8sMutex.Unlock() + if fake.IsCFOnK8sStub != nil { + return fake.IsCFOnK8sStub() + } + if specificReturn { + return ret.result1 + } + fakeReturns := fake.isCFOnK8sReturns + return fakeReturns.result1 +} + +func (fake *FakeConfig) IsCFOnK8sCallCount() int { + fake.isCFOnK8sMutex.RLock() + defer fake.isCFOnK8sMutex.RUnlock() + return len(fake.isCFOnK8sArgsForCall) +} + +func (fake *FakeConfig) IsCFOnK8sCalls(stub func() bool) { + fake.isCFOnK8sMutex.Lock() + defer fake.isCFOnK8sMutex.Unlock() + fake.IsCFOnK8sStub = stub +} + +func (fake *FakeConfig) IsCFOnK8sReturns(result1 bool) { + fake.isCFOnK8sMutex.Lock() + defer fake.isCFOnK8sMutex.Unlock() + fake.IsCFOnK8sStub = nil + fake.isCFOnK8sReturns = struct { + result1 bool + }{result1} +} + +func (fake *FakeConfig) IsCFOnK8sReturnsOnCall(i int, result1 bool) { + fake.isCFOnK8sMutex.Lock() + defer fake.isCFOnK8sMutex.Unlock() + fake.IsCFOnK8sStub = nil + if fake.isCFOnK8sReturnsOnCall == nil { + fake.isCFOnK8sReturnsOnCall = make(map[int]struct { + result1 bool + }) + } + fake.isCFOnK8sReturnsOnCall[i] = struct { + result1 bool + }{result1} +} + func (fake *FakeConfig) IsTTY() bool { fake.isTTYMutex.Lock() ret, specificReturn := fake.isTTYReturnsOnCall[len(fake.isTTYArgsForCall)] fake.isTTYArgsForCall = append(fake.isTTYArgsForCall, struct { }{}) - stub := fake.IsTTYStub - fakeReturns := fake.isTTYReturns fake.recordInvocation("IsTTY", []interface{}{}) fake.isTTYMutex.Unlock() - if stub != nil { - return stub() + if fake.IsTTYStub != nil { + return fake.IsTTYStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.isTTYReturns return fakeReturns.result1 } @@ -1668,16 +1715,15 @@ func (fake *FakeConfig) Locale() string { ret, specificReturn := fake.localeReturnsOnCall[len(fake.localeArgsForCall)] fake.localeArgsForCall = append(fake.localeArgsForCall, struct { }{}) - stub := fake.LocaleStub - fakeReturns := fake.localeReturns fake.recordInvocation("Locale", []interface{}{}) fake.localeMutex.Unlock() - if stub != nil { - return stub() + if fake.LocaleStub != nil { + return fake.LocaleStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.localeReturns return fakeReturns.result1 } @@ -1721,16 +1767,15 @@ func (fake *FakeConfig) LogCacheEndpoint() string { ret, specificReturn := fake.logCacheEndpointReturnsOnCall[len(fake.logCacheEndpointArgsForCall)] fake.logCacheEndpointArgsForCall = append(fake.logCacheEndpointArgsForCall, struct { }{}) - stub := fake.LogCacheEndpointStub - fakeReturns := fake.logCacheEndpointReturns fake.recordInvocation("LogCacheEndpoint", []interface{}{}) fake.logCacheEndpointMutex.Unlock() - if stub != nil { - return stub() + if fake.LogCacheEndpointStub != nil { + return fake.LogCacheEndpointStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.logCacheEndpointReturns return fakeReturns.result1 } @@ -1774,16 +1819,15 @@ func (fake *FakeConfig) MinCLIVersion() string { ret, specificReturn := fake.minCLIVersionReturnsOnCall[len(fake.minCLIVersionArgsForCall)] fake.minCLIVersionArgsForCall = append(fake.minCLIVersionArgsForCall, struct { }{}) - stub := fake.MinCLIVersionStub - fakeReturns := fake.minCLIVersionReturns fake.recordInvocation("MinCLIVersion", []interface{}{}) fake.minCLIVersionMutex.Unlock() - if stub != nil { - return stub() + if fake.MinCLIVersionStub != nil { + return fake.MinCLIVersionStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.minCLIVersionReturns return fakeReturns.result1 } @@ -1827,16 +1871,15 @@ func (fake *FakeConfig) NOAARequestRetryCount() int { ret, specificReturn := fake.nOAARequestRetryCountReturnsOnCall[len(fake.nOAARequestRetryCountArgsForCall)] fake.nOAARequestRetryCountArgsForCall = append(fake.nOAARequestRetryCountArgsForCall, struct { }{}) - stub := fake.NOAARequestRetryCountStub - fakeReturns := fake.nOAARequestRetryCountReturns fake.recordInvocation("NOAARequestRetryCount", []interface{}{}) fake.nOAARequestRetryCountMutex.Unlock() - if stub != nil { - return stub() + if fake.NOAARequestRetryCountStub != nil { + return fake.NOAARequestRetryCountStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.nOAARequestRetryCountReturns return fakeReturns.result1 } @@ -1880,16 +1923,15 @@ func (fake *FakeConfig) NetworkPolicyV1Endpoint() string { ret, specificReturn := fake.networkPolicyV1EndpointReturnsOnCall[len(fake.networkPolicyV1EndpointArgsForCall)] fake.networkPolicyV1EndpointArgsForCall = append(fake.networkPolicyV1EndpointArgsForCall, struct { }{}) - stub := fake.NetworkPolicyV1EndpointStub - fakeReturns := fake.networkPolicyV1EndpointReturns fake.recordInvocation("NetworkPolicyV1Endpoint", []interface{}{}) fake.networkPolicyV1EndpointMutex.Unlock() - if stub != nil { - return stub() + if fake.NetworkPolicyV1EndpointStub != nil { + return fake.NetworkPolicyV1EndpointStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.networkPolicyV1EndpointReturns return fakeReturns.result1 } @@ -1933,16 +1975,15 @@ func (fake *FakeConfig) OverallPollingTimeout() time.Duration { ret, specificReturn := fake.overallPollingTimeoutReturnsOnCall[len(fake.overallPollingTimeoutArgsForCall)] fake.overallPollingTimeoutArgsForCall = append(fake.overallPollingTimeoutArgsForCall, struct { }{}) - stub := fake.OverallPollingTimeoutStub - fakeReturns := fake.overallPollingTimeoutReturns fake.recordInvocation("OverallPollingTimeout", []interface{}{}) fake.overallPollingTimeoutMutex.Unlock() - if stub != nil { - return stub() + if fake.OverallPollingTimeoutStub != nil { + return fake.OverallPollingTimeoutStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.overallPollingTimeoutReturns return fakeReturns.result1 } @@ -1986,16 +2027,15 @@ func (fake *FakeConfig) PluginHome() string { ret, specificReturn := fake.pluginHomeReturnsOnCall[len(fake.pluginHomeArgsForCall)] fake.pluginHomeArgsForCall = append(fake.pluginHomeArgsForCall, struct { }{}) - stub := fake.PluginHomeStub - fakeReturns := fake.pluginHomeReturns fake.recordInvocation("PluginHome", []interface{}{}) fake.pluginHomeMutex.Unlock() - if stub != nil { - return stub() + if fake.PluginHomeStub != nil { + return fake.PluginHomeStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.pluginHomeReturns return fakeReturns.result1 } @@ -2039,16 +2079,15 @@ func (fake *FakeConfig) PluginRepositories() []configv3.PluginRepository { ret, specificReturn := fake.pluginRepositoriesReturnsOnCall[len(fake.pluginRepositoriesArgsForCall)] fake.pluginRepositoriesArgsForCall = append(fake.pluginRepositoriesArgsForCall, struct { }{}) - stub := fake.PluginRepositoriesStub - fakeReturns := fake.pluginRepositoriesReturns fake.recordInvocation("PluginRepositories", []interface{}{}) fake.pluginRepositoriesMutex.Unlock() - if stub != nil { - return stub() + if fake.PluginRepositoriesStub != nil { + return fake.PluginRepositoriesStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.pluginRepositoriesReturns return fakeReturns.result1 } @@ -2092,16 +2131,15 @@ func (fake *FakeConfig) Plugins() []configv3.Plugin { ret, specificReturn := fake.pluginsReturnsOnCall[len(fake.pluginsArgsForCall)] fake.pluginsArgsForCall = append(fake.pluginsArgsForCall, struct { }{}) - stub := fake.PluginsStub - fakeReturns := fake.pluginsReturns fake.recordInvocation("Plugins", []interface{}{}) fake.pluginsMutex.Unlock() - if stub != nil { - return stub() + if fake.PluginsStub != nil { + return fake.PluginsStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.pluginsReturns return fakeReturns.result1 } @@ -2145,16 +2183,15 @@ func (fake *FakeConfig) PollingInterval() time.Duration { ret, specificReturn := fake.pollingIntervalReturnsOnCall[len(fake.pollingIntervalArgsForCall)] fake.pollingIntervalArgsForCall = append(fake.pollingIntervalArgsForCall, struct { }{}) - stub := fake.PollingIntervalStub - fakeReturns := fake.pollingIntervalReturns fake.recordInvocation("PollingInterval", []interface{}{}) fake.pollingIntervalMutex.Unlock() - if stub != nil { - return stub() + if fake.PollingIntervalStub != nil { + return fake.PollingIntervalStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.pollingIntervalReturns return fakeReturns.result1 } @@ -2198,16 +2235,15 @@ func (fake *FakeConfig) RefreshToken() string { ret, specificReturn := fake.refreshTokenReturnsOnCall[len(fake.refreshTokenArgsForCall)] fake.refreshTokenArgsForCall = append(fake.refreshTokenArgsForCall, struct { }{}) - stub := fake.RefreshTokenStub - fakeReturns := fake.refreshTokenReturns fake.recordInvocation("RefreshToken", []interface{}{}) fake.refreshTokenMutex.Unlock() - if stub != nil { - return stub() + if fake.RefreshTokenStub != nil { + return fake.RefreshTokenStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.refreshTokenReturns return fakeReturns.result1 } @@ -2251,10 +2287,9 @@ func (fake *FakeConfig) RemovePlugin(arg1 string) { fake.removePluginArgsForCall = append(fake.removePluginArgsForCall, struct { arg1 string }{arg1}) - stub := fake.RemovePluginStub fake.recordInvocation("RemovePlugin", []interface{}{arg1}) fake.removePluginMutex.Unlock() - if stub != nil { + if fake.RemovePluginStub != nil { fake.RemovePluginStub(arg1) } } @@ -2283,16 +2318,15 @@ func (fake *FakeConfig) RequestRetryCount() int { ret, specificReturn := fake.requestRetryCountReturnsOnCall[len(fake.requestRetryCountArgsForCall)] fake.requestRetryCountArgsForCall = append(fake.requestRetryCountArgsForCall, struct { }{}) - stub := fake.RequestRetryCountStub - fakeReturns := fake.requestRetryCountReturns fake.recordInvocation("RequestRetryCount", []interface{}{}) fake.requestRetryCountMutex.Unlock() - if stub != nil { - return stub() + if fake.RequestRetryCountStub != nil { + return fake.RequestRetryCountStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.requestRetryCountReturns return fakeReturns.result1 } @@ -2336,16 +2370,15 @@ func (fake *FakeConfig) RoutingEndpoint() string { ret, specificReturn := fake.routingEndpointReturnsOnCall[len(fake.routingEndpointArgsForCall)] fake.routingEndpointArgsForCall = append(fake.routingEndpointArgsForCall, struct { }{}) - stub := fake.RoutingEndpointStub - fakeReturns := fake.routingEndpointReturns fake.recordInvocation("RoutingEndpoint", []interface{}{}) fake.routingEndpointMutex.Unlock() - if stub != nil { - return stub() + if fake.RoutingEndpointStub != nil { + return fake.RoutingEndpointStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.routingEndpointReturns return fakeReturns.result1 } @@ -2389,16 +2422,15 @@ func (fake *FakeConfig) SSHOAuthClient() string { ret, specificReturn := fake.sSHOAuthClientReturnsOnCall[len(fake.sSHOAuthClientArgsForCall)] fake.sSHOAuthClientArgsForCall = append(fake.sSHOAuthClientArgsForCall, struct { }{}) - stub := fake.SSHOAuthClientStub - fakeReturns := fake.sSHOAuthClientReturns fake.recordInvocation("SSHOAuthClient", []interface{}{}) fake.sSHOAuthClientMutex.Unlock() - if stub != nil { - return stub() + if fake.SSHOAuthClientStub != nil { + return fake.SSHOAuthClientStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.sSHOAuthClientReturns return fakeReturns.result1 } @@ -2442,10 +2474,9 @@ func (fake *FakeConfig) SetAccessToken(arg1 string) { fake.setAccessTokenArgsForCall = append(fake.setAccessTokenArgsForCall, struct { arg1 string }{arg1}) - stub := fake.SetAccessTokenStub fake.recordInvocation("SetAccessToken", []interface{}{arg1}) fake.setAccessTokenMutex.Unlock() - if stub != nil { + if fake.SetAccessTokenStub != nil { fake.SetAccessTokenStub(arg1) } } @@ -2474,10 +2505,9 @@ func (fake *FakeConfig) SetAsyncTimeout(arg1 int) { fake.setAsyncTimeoutArgsForCall = append(fake.setAsyncTimeoutArgsForCall, struct { arg1 int }{arg1}) - stub := fake.SetAsyncTimeoutStub fake.recordInvocation("SetAsyncTimeout", []interface{}{arg1}) fake.setAsyncTimeoutMutex.Unlock() - if stub != nil { + if fake.SetAsyncTimeoutStub != nil { fake.SetAsyncTimeoutStub(arg1) } } @@ -2506,10 +2536,9 @@ func (fake *FakeConfig) SetColorEnabled(arg1 string) { fake.setColorEnabledArgsForCall = append(fake.setColorEnabledArgsForCall, struct { arg1 string }{arg1}) - stub := fake.SetColorEnabledStub fake.recordInvocation("SetColorEnabled", []interface{}{arg1}) fake.setColorEnabledMutex.Unlock() - if stub != nil { + if fake.SetColorEnabledStub != nil { fake.SetColorEnabledStub(arg1) } } @@ -2533,15 +2562,45 @@ func (fake *FakeConfig) SetColorEnabledArgsForCall(i int) string { return argsForCall.arg1 } +func (fake *FakeConfig) SetKubernetesAuthInfo(arg1 string) { + fake.setKubernetesAuthInfoMutex.Lock() + fake.setKubernetesAuthInfoArgsForCall = append(fake.setKubernetesAuthInfoArgsForCall, struct { + arg1 string + }{arg1}) + fake.recordInvocation("SetKubernetesAuthInfo", []interface{}{arg1}) + fake.setKubernetesAuthInfoMutex.Unlock() + if fake.SetKubernetesAuthInfoStub != nil { + fake.SetKubernetesAuthInfoStub(arg1) + } +} + +func (fake *FakeConfig) SetKubernetesAuthInfoCallCount() int { + fake.setKubernetesAuthInfoMutex.RLock() + defer fake.setKubernetesAuthInfoMutex.RUnlock() + return len(fake.setKubernetesAuthInfoArgsForCall) +} + +func (fake *FakeConfig) SetKubernetesAuthInfoCalls(stub func(string)) { + fake.setKubernetesAuthInfoMutex.Lock() + defer fake.setKubernetesAuthInfoMutex.Unlock() + fake.SetKubernetesAuthInfoStub = stub +} + +func (fake *FakeConfig) SetKubernetesAuthInfoArgsForCall(i int) string { + fake.setKubernetesAuthInfoMutex.RLock() + defer fake.setKubernetesAuthInfoMutex.RUnlock() + argsForCall := fake.setKubernetesAuthInfoArgsForCall[i] + return argsForCall.arg1 +} + func (fake *FakeConfig) SetLocale(arg1 string) { fake.setLocaleMutex.Lock() fake.setLocaleArgsForCall = append(fake.setLocaleArgsForCall, struct { arg1 string }{arg1}) - stub := fake.SetLocaleStub fake.recordInvocation("SetLocale", []interface{}{arg1}) fake.setLocaleMutex.Unlock() - if stub != nil { + if fake.SetLocaleStub != nil { fake.SetLocaleStub(arg1) } } @@ -2570,10 +2629,9 @@ func (fake *FakeConfig) SetMinCLIVersion(arg1 string) { fake.setMinCLIVersionArgsForCall = append(fake.setMinCLIVersionArgsForCall, struct { arg1 string }{arg1}) - stub := fake.SetMinCLIVersionStub fake.recordInvocation("SetMinCLIVersion", []interface{}{arg1}) fake.setMinCLIVersionMutex.Unlock() - if stub != nil { + if fake.SetMinCLIVersionStub != nil { fake.SetMinCLIVersionStub(arg1) } } @@ -2603,10 +2661,9 @@ func (fake *FakeConfig) SetOrganizationInformation(arg1 string, arg2 string) { arg1 string arg2 string }{arg1, arg2}) - stub := fake.SetOrganizationInformationStub fake.recordInvocation("SetOrganizationInformation", []interface{}{arg1, arg2}) fake.setOrganizationInformationMutex.Unlock() - if stub != nil { + if fake.SetOrganizationInformationStub != nil { fake.SetOrganizationInformationStub(arg1, arg2) } } @@ -2635,10 +2692,9 @@ func (fake *FakeConfig) SetRefreshToken(arg1 string) { fake.setRefreshTokenArgsForCall = append(fake.setRefreshTokenArgsForCall, struct { arg1 string }{arg1}) - stub := fake.SetRefreshTokenStub fake.recordInvocation("SetRefreshToken", []interface{}{arg1}) fake.setRefreshTokenMutex.Unlock() - if stub != nil { + if fake.SetRefreshTokenStub != nil { fake.SetRefreshTokenStub(arg1) } } @@ -2669,10 +2725,9 @@ func (fake *FakeConfig) SetSpaceInformation(arg1 string, arg2 string, arg3 bool) arg2 string arg3 bool }{arg1, arg2, arg3}) - stub := fake.SetSpaceInformationStub fake.recordInvocation("SetSpaceInformation", []interface{}{arg1, arg2, arg3}) fake.setSpaceInformationMutex.Unlock() - if stub != nil { + if fake.SetSpaceInformationStub != nil { fake.SetSpaceInformationStub(arg1, arg2, arg3) } } @@ -2701,10 +2756,9 @@ func (fake *FakeConfig) SetTargetInformation(arg1 configv3.TargetInformationArgs fake.setTargetInformationArgsForCall = append(fake.setTargetInformationArgsForCall, struct { arg1 configv3.TargetInformationArgs }{arg1}) - stub := fake.SetTargetInformationStub fake.recordInvocation("SetTargetInformation", []interface{}{arg1}) fake.setTargetInformationMutex.Unlock() - if stub != nil { + if fake.SetTargetInformationStub != nil { fake.SetTargetInformationStub(arg1) } } @@ -2735,10 +2789,9 @@ func (fake *FakeConfig) SetTokenInformation(arg1 string, arg2 string, arg3 strin arg2 string arg3 string }{arg1, arg2, arg3}) - stub := fake.SetTokenInformationStub fake.recordInvocation("SetTokenInformation", []interface{}{arg1, arg2, arg3}) fake.setTokenInformationMutex.Unlock() - if stub != nil { + if fake.SetTokenInformationStub != nil { fake.SetTokenInformationStub(arg1, arg2, arg3) } } @@ -2767,10 +2820,9 @@ func (fake *FakeConfig) SetTrace(arg1 string) { fake.setTraceArgsForCall = append(fake.setTraceArgsForCall, struct { arg1 string }{arg1}) - stub := fake.SetTraceStub fake.recordInvocation("SetTrace", []interface{}{arg1}) fake.setTraceMutex.Unlock() - if stub != nil { + if fake.SetTraceStub != nil { fake.SetTraceStub(arg1) } } @@ -2800,10 +2852,9 @@ func (fake *FakeConfig) SetUAAClientCredentials(arg1 string, arg2 string) { arg1 string arg2 string }{arg1, arg2}) - stub := fake.SetUAAClientCredentialsStub fake.recordInvocation("SetUAAClientCredentials", []interface{}{arg1, arg2}) fake.setUAAClientCredentialsMutex.Unlock() - if stub != nil { + if fake.SetUAAClientCredentialsStub != nil { fake.SetUAAClientCredentialsStub(arg1, arg2) } } @@ -2832,10 +2883,9 @@ func (fake *FakeConfig) SetUAAEndpoint(arg1 string) { fake.setUAAEndpointArgsForCall = append(fake.setUAAEndpointArgsForCall, struct { arg1 string }{arg1}) - stub := fake.SetUAAEndpointStub fake.recordInvocation("SetUAAEndpoint", []interface{}{arg1}) fake.setUAAEndpointMutex.Unlock() - if stub != nil { + if fake.SetUAAEndpointStub != nil { fake.SetUAAEndpointStub(arg1) } } @@ -2864,10 +2914,9 @@ func (fake *FakeConfig) SetUAAGrantType(arg1 string) { fake.setUAAGrantTypeArgsForCall = append(fake.setUAAGrantTypeArgsForCall, struct { arg1 string }{arg1}) - stub := fake.SetUAAGrantTypeStub fake.recordInvocation("SetUAAGrantType", []interface{}{arg1}) fake.setUAAGrantTypeMutex.Unlock() - if stub != nil { + if fake.SetUAAGrantTypeStub != nil { fake.SetUAAGrantTypeStub(arg1) } } @@ -2896,16 +2945,15 @@ func (fake *FakeConfig) SkipSSLValidation() bool { ret, specificReturn := fake.skipSSLValidationReturnsOnCall[len(fake.skipSSLValidationArgsForCall)] fake.skipSSLValidationArgsForCall = append(fake.skipSSLValidationArgsForCall, struct { }{}) - stub := fake.SkipSSLValidationStub - fakeReturns := fake.skipSSLValidationReturns fake.recordInvocation("SkipSSLValidation", []interface{}{}) fake.skipSSLValidationMutex.Unlock() - if stub != nil { - return stub() + if fake.SkipSSLValidationStub != nil { + return fake.SkipSSLValidationStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.skipSSLValidationReturns return fakeReturns.result1 } @@ -2949,16 +2997,15 @@ func (fake *FakeConfig) StagingTimeout() time.Duration { ret, specificReturn := fake.stagingTimeoutReturnsOnCall[len(fake.stagingTimeoutArgsForCall)] fake.stagingTimeoutArgsForCall = append(fake.stagingTimeoutArgsForCall, struct { }{}) - stub := fake.StagingTimeoutStub - fakeReturns := fake.stagingTimeoutReturns fake.recordInvocation("StagingTimeout", []interface{}{}) fake.stagingTimeoutMutex.Unlock() - if stub != nil { - return stub() + if fake.StagingTimeoutStub != nil { + return fake.StagingTimeoutStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.stagingTimeoutReturns return fakeReturns.result1 } @@ -3002,16 +3049,15 @@ func (fake *FakeConfig) StartupTimeout() time.Duration { ret, specificReturn := fake.startupTimeoutReturnsOnCall[len(fake.startupTimeoutArgsForCall)] fake.startupTimeoutArgsForCall = append(fake.startupTimeoutArgsForCall, struct { }{}) - stub := fake.StartupTimeoutStub - fakeReturns := fake.startupTimeoutReturns fake.recordInvocation("StartupTimeout", []interface{}{}) fake.startupTimeoutMutex.Unlock() - if stub != nil { - return stub() + if fake.StartupTimeoutStub != nil { + return fake.StartupTimeoutStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.startupTimeoutReturns return fakeReturns.result1 } @@ -3055,16 +3101,15 @@ func (fake *FakeConfig) Target() string { ret, specificReturn := fake.targetReturnsOnCall[len(fake.targetArgsForCall)] fake.targetArgsForCall = append(fake.targetArgsForCall, struct { }{}) - stub := fake.TargetStub - fakeReturns := fake.targetReturns fake.recordInvocation("Target", []interface{}{}) fake.targetMutex.Unlock() - if stub != nil { - return stub() + if fake.TargetStub != nil { + return fake.TargetStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.targetReturns return fakeReturns.result1 } @@ -3108,16 +3153,15 @@ func (fake *FakeConfig) TargetedOrganization() configv3.Organization { ret, specificReturn := fake.targetedOrganizationReturnsOnCall[len(fake.targetedOrganizationArgsForCall)] fake.targetedOrganizationArgsForCall = append(fake.targetedOrganizationArgsForCall, struct { }{}) - stub := fake.TargetedOrganizationStub - fakeReturns := fake.targetedOrganizationReturns fake.recordInvocation("TargetedOrganization", []interface{}{}) fake.targetedOrganizationMutex.Unlock() - if stub != nil { - return stub() + if fake.TargetedOrganizationStub != nil { + return fake.TargetedOrganizationStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.targetedOrganizationReturns return fakeReturns.result1 } @@ -3161,16 +3205,15 @@ func (fake *FakeConfig) TargetedOrganizationName() string { ret, specificReturn := fake.targetedOrganizationNameReturnsOnCall[len(fake.targetedOrganizationNameArgsForCall)] fake.targetedOrganizationNameArgsForCall = append(fake.targetedOrganizationNameArgsForCall, struct { }{}) - stub := fake.TargetedOrganizationNameStub - fakeReturns := fake.targetedOrganizationNameReturns fake.recordInvocation("TargetedOrganizationName", []interface{}{}) fake.targetedOrganizationNameMutex.Unlock() - if stub != nil { - return stub() + if fake.TargetedOrganizationNameStub != nil { + return fake.TargetedOrganizationNameStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.targetedOrganizationNameReturns return fakeReturns.result1 } @@ -3214,16 +3257,15 @@ func (fake *FakeConfig) TargetedSpace() configv3.Space { ret, specificReturn := fake.targetedSpaceReturnsOnCall[len(fake.targetedSpaceArgsForCall)] fake.targetedSpaceArgsForCall = append(fake.targetedSpaceArgsForCall, struct { }{}) - stub := fake.TargetedSpaceStub - fakeReturns := fake.targetedSpaceReturns fake.recordInvocation("TargetedSpace", []interface{}{}) fake.targetedSpaceMutex.Unlock() - if stub != nil { - return stub() + if fake.TargetedSpaceStub != nil { + return fake.TargetedSpaceStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.targetedSpaceReturns return fakeReturns.result1 } @@ -3267,16 +3309,15 @@ func (fake *FakeConfig) TerminalWidth() int { ret, specificReturn := fake.terminalWidthReturnsOnCall[len(fake.terminalWidthArgsForCall)] fake.terminalWidthArgsForCall = append(fake.terminalWidthArgsForCall, struct { }{}) - stub := fake.TerminalWidthStub - fakeReturns := fake.terminalWidthReturns fake.recordInvocation("TerminalWidth", []interface{}{}) fake.terminalWidthMutex.Unlock() - if stub != nil { - return stub() + if fake.TerminalWidthStub != nil { + return fake.TerminalWidthStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.terminalWidthReturns return fakeReturns.result1 } @@ -3320,16 +3361,15 @@ func (fake *FakeConfig) UAADisableKeepAlives() bool { ret, specificReturn := fake.uAADisableKeepAlivesReturnsOnCall[len(fake.uAADisableKeepAlivesArgsForCall)] fake.uAADisableKeepAlivesArgsForCall = append(fake.uAADisableKeepAlivesArgsForCall, struct { }{}) - stub := fake.UAADisableKeepAlivesStub - fakeReturns := fake.uAADisableKeepAlivesReturns fake.recordInvocation("UAADisableKeepAlives", []interface{}{}) fake.uAADisableKeepAlivesMutex.Unlock() - if stub != nil { - return stub() + if fake.UAADisableKeepAlivesStub != nil { + return fake.UAADisableKeepAlivesStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.uAADisableKeepAlivesReturns return fakeReturns.result1 } @@ -3373,16 +3413,15 @@ func (fake *FakeConfig) UAAEndpoint() string { ret, specificReturn := fake.uAAEndpointReturnsOnCall[len(fake.uAAEndpointArgsForCall)] fake.uAAEndpointArgsForCall = append(fake.uAAEndpointArgsForCall, struct { }{}) - stub := fake.UAAEndpointStub - fakeReturns := fake.uAAEndpointReturns fake.recordInvocation("UAAEndpoint", []interface{}{}) fake.uAAEndpointMutex.Unlock() - if stub != nil { - return stub() + if fake.UAAEndpointStub != nil { + return fake.UAAEndpointStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.uAAEndpointReturns return fakeReturns.result1 } @@ -3426,16 +3465,15 @@ func (fake *FakeConfig) UAAGrantType() string { ret, specificReturn := fake.uAAGrantTypeReturnsOnCall[len(fake.uAAGrantTypeArgsForCall)] fake.uAAGrantTypeArgsForCall = append(fake.uAAGrantTypeArgsForCall, struct { }{}) - stub := fake.UAAGrantTypeStub - fakeReturns := fake.uAAGrantTypeReturns fake.recordInvocation("UAAGrantType", []interface{}{}) fake.uAAGrantTypeMutex.Unlock() - if stub != nil { - return stub() + if fake.UAAGrantTypeStub != nil { + return fake.UAAGrantTypeStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.uAAGrantTypeReturns return fakeReturns.result1 } @@ -3479,16 +3517,15 @@ func (fake *FakeConfig) UAAOAuthClient() string { ret, specificReturn := fake.uAAOAuthClientReturnsOnCall[len(fake.uAAOAuthClientArgsForCall)] fake.uAAOAuthClientArgsForCall = append(fake.uAAOAuthClientArgsForCall, struct { }{}) - stub := fake.UAAOAuthClientStub - fakeReturns := fake.uAAOAuthClientReturns fake.recordInvocation("UAAOAuthClient", []interface{}{}) fake.uAAOAuthClientMutex.Unlock() - if stub != nil { - return stub() + if fake.UAAOAuthClientStub != nil { + return fake.UAAOAuthClientStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.uAAOAuthClientReturns return fakeReturns.result1 } @@ -3532,16 +3569,15 @@ func (fake *FakeConfig) UAAOAuthClientSecret() string { ret, specificReturn := fake.uAAOAuthClientSecretReturnsOnCall[len(fake.uAAOAuthClientSecretArgsForCall)] fake.uAAOAuthClientSecretArgsForCall = append(fake.uAAOAuthClientSecretArgsForCall, struct { }{}) - stub := fake.UAAOAuthClientSecretStub - fakeReturns := fake.uAAOAuthClientSecretReturns fake.recordInvocation("UAAOAuthClientSecret", []interface{}{}) fake.uAAOAuthClientSecretMutex.Unlock() - if stub != nil { - return stub() + if fake.UAAOAuthClientSecretStub != nil { + return fake.UAAOAuthClientSecretStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.uAAOAuthClientSecretReturns return fakeReturns.result1 } @@ -3584,10 +3620,9 @@ func (fake *FakeConfig) UnsetOrganizationAndSpaceInformation() { fake.unsetOrganizationAndSpaceInformationMutex.Lock() fake.unsetOrganizationAndSpaceInformationArgsForCall = append(fake.unsetOrganizationAndSpaceInformationArgsForCall, struct { }{}) - stub := fake.UnsetOrganizationAndSpaceInformationStub fake.recordInvocation("UnsetOrganizationAndSpaceInformation", []interface{}{}) fake.unsetOrganizationAndSpaceInformationMutex.Unlock() - if stub != nil { + if fake.UnsetOrganizationAndSpaceInformationStub != nil { fake.UnsetOrganizationAndSpaceInformationStub() } } @@ -3608,10 +3643,9 @@ func (fake *FakeConfig) UnsetSpaceInformation() { fake.unsetSpaceInformationMutex.Lock() fake.unsetSpaceInformationArgsForCall = append(fake.unsetSpaceInformationArgsForCall, struct { }{}) - stub := fake.UnsetSpaceInformationStub fake.recordInvocation("UnsetSpaceInformation", []interface{}{}) fake.unsetSpaceInformationMutex.Unlock() - if stub != nil { + if fake.UnsetSpaceInformationStub != nil { fake.UnsetSpaceInformationStub() } } @@ -3632,10 +3666,9 @@ func (fake *FakeConfig) UnsetUserInformation() { fake.unsetUserInformationMutex.Lock() fake.unsetUserInformationArgsForCall = append(fake.unsetUserInformationArgsForCall, struct { }{}) - stub := fake.UnsetUserInformationStub fake.recordInvocation("UnsetUserInformation", []interface{}{}) fake.unsetUserInformationMutex.Unlock() - if stub != nil { + if fake.UnsetUserInformationStub != nil { fake.UnsetUserInformationStub() } } @@ -3658,10 +3691,9 @@ func (fake *FakeConfig) V7SetSpaceInformation(arg1 string, arg2 string) { arg1 string arg2 string }{arg1, arg2}) - stub := fake.V7SetSpaceInformationStub fake.recordInvocation("V7SetSpaceInformation", []interface{}{arg1, arg2}) fake.v7SetSpaceInformationMutex.Unlock() - if stub != nil { + if fake.V7SetSpaceInformationStub != nil { fake.V7SetSpaceInformationStub(arg1, arg2) } } @@ -3690,16 +3722,15 @@ func (fake *FakeConfig) Verbose() (bool, []string) { ret, specificReturn := fake.verboseReturnsOnCall[len(fake.verboseArgsForCall)] fake.verboseArgsForCall = append(fake.verboseArgsForCall, struct { }{}) - stub := fake.VerboseStub - fakeReturns := fake.verboseReturns fake.recordInvocation("Verbose", []interface{}{}) fake.verboseMutex.Unlock() - if stub != nil { - return stub() + if fake.VerboseStub != nil { + return fake.VerboseStub() } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.verboseReturns return fakeReturns.result1, fakeReturns.result2 } @@ -3746,16 +3777,15 @@ func (fake *FakeConfig) WriteConfig() error { ret, specificReturn := fake.writeConfigReturnsOnCall[len(fake.writeConfigArgsForCall)] fake.writeConfigArgsForCall = append(fake.writeConfigArgsForCall, struct { }{}) - stub := fake.WriteConfigStub - fakeReturns := fake.writeConfigReturns fake.recordInvocation("WriteConfig", []interface{}{}) fake.writeConfigMutex.Unlock() - if stub != nil { - return stub() + if fake.WriteConfigStub != nil { + return fake.WriteConfigStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.writeConfigReturns return fakeReturns.result1 } @@ -3799,16 +3829,15 @@ func (fake *FakeConfig) WritePluginConfig() error { ret, specificReturn := fake.writePluginConfigReturnsOnCall[len(fake.writePluginConfigArgsForCall)] fake.writePluginConfigArgsForCall = append(fake.writePluginConfigArgsForCall, struct { }{}) - stub := fake.WritePluginConfigStub - fakeReturns := fake.writePluginConfigReturns fake.recordInvocation("WritePluginConfig", []interface{}{}) fake.writePluginConfigMutex.Unlock() - if stub != nil { - return stub() + if fake.WritePluginConfigStub != nil { + return fake.WritePluginConfigStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.writePluginConfigReturns return fakeReturns.result1 } @@ -3888,6 +3917,8 @@ func (fake *FakeConfig) Invocations() map[string][][]interface{} { defer fake.hasTargetedOrganizationMutex.RUnlock() fake.hasTargetedSpaceMutex.RLock() defer fake.hasTargetedSpaceMutex.RUnlock() + fake.isCFOnK8sMutex.RLock() + defer fake.isCFOnK8sMutex.RUnlock() fake.isTTYMutex.RLock() defer fake.isTTYMutex.RUnlock() fake.localeMutex.RLock() @@ -3926,6 +3957,8 @@ func (fake *FakeConfig) Invocations() map[string][][]interface{} { defer fake.setAsyncTimeoutMutex.RUnlock() fake.setColorEnabledMutex.RLock() defer fake.setColorEnabledMutex.RUnlock() + fake.setKubernetesAuthInfoMutex.RLock() + defer fake.setKubernetesAuthInfoMutex.RUnlock() fake.setLocaleMutex.RLock() defer fake.setLocaleMutex.RUnlock() fake.setMinCLIVersionMutex.RLock() diff --git a/command/commandfakes/fake_shared_actor.go b/command/commandfakes/fake_shared_actor.go index b47add345b8..fec3b1b77d3 100644 --- a/command/commandfakes/fake_shared_actor.go +++ b/command/commandfakes/fake_shared_actor.go @@ -85,16 +85,15 @@ func (fake *FakeSharedActor) CheckTarget(arg1 bool, arg2 bool) error { arg1 bool arg2 bool }{arg1, arg2}) - stub := fake.CheckTargetStub - fakeReturns := fake.checkTargetReturns fake.recordInvocation("CheckTarget", []interface{}{arg1, arg2}) fake.checkTargetMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) + if fake.CheckTargetStub != nil { + return fake.CheckTargetStub(arg1, arg2) } if specificReturn { return ret.result1 } + fakeReturns := fake.checkTargetReturns return fakeReturns.result1 } @@ -145,16 +144,15 @@ func (fake *FakeSharedActor) IsLoggedIn() bool { ret, specificReturn := fake.isLoggedInReturnsOnCall[len(fake.isLoggedInArgsForCall)] fake.isLoggedInArgsForCall = append(fake.isLoggedInArgsForCall, struct { }{}) - stub := fake.IsLoggedInStub - fakeReturns := fake.isLoggedInReturns fake.recordInvocation("IsLoggedIn", []interface{}{}) fake.isLoggedInMutex.Unlock() - if stub != nil { - return stub() + if fake.IsLoggedInStub != nil { + return fake.IsLoggedInStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.isLoggedInReturns return fakeReturns.result1 } @@ -198,16 +196,15 @@ func (fake *FakeSharedActor) IsOrgTargeted() bool { ret, specificReturn := fake.isOrgTargetedReturnsOnCall[len(fake.isOrgTargetedArgsForCall)] fake.isOrgTargetedArgsForCall = append(fake.isOrgTargetedArgsForCall, struct { }{}) - stub := fake.IsOrgTargetedStub - fakeReturns := fake.isOrgTargetedReturns fake.recordInvocation("IsOrgTargeted", []interface{}{}) fake.isOrgTargetedMutex.Unlock() - if stub != nil { - return stub() + if fake.IsOrgTargetedStub != nil { + return fake.IsOrgTargetedStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.isOrgTargetedReturns return fakeReturns.result1 } @@ -251,16 +248,15 @@ func (fake *FakeSharedActor) IsSpaceTargeted() bool { ret, specificReturn := fake.isSpaceTargetedReturnsOnCall[len(fake.isSpaceTargetedArgsForCall)] fake.isSpaceTargetedArgsForCall = append(fake.isSpaceTargetedArgsForCall, struct { }{}) - stub := fake.IsSpaceTargetedStub - fakeReturns := fake.isSpaceTargetedReturns fake.recordInvocation("IsSpaceTargeted", []interface{}{}) fake.isSpaceTargetedMutex.Unlock() - if stub != nil { - return stub() + if fake.IsSpaceTargetedStub != nil { + return fake.IsSpaceTargetedStub() } if specificReturn { return ret.result1 } + fakeReturns := fake.isSpaceTargetedReturns return fakeReturns.result1 } @@ -304,16 +300,15 @@ func (fake *FakeSharedActor) RequireCurrentUser() (string, error) { ret, specificReturn := fake.requireCurrentUserReturnsOnCall[len(fake.requireCurrentUserArgsForCall)] fake.requireCurrentUserArgsForCall = append(fake.requireCurrentUserArgsForCall, struct { }{}) - stub := fake.RequireCurrentUserStub - fakeReturns := fake.requireCurrentUserReturns fake.recordInvocation("RequireCurrentUser", []interface{}{}) fake.requireCurrentUserMutex.Unlock() - if stub != nil { - return stub() + if fake.RequireCurrentUserStub != nil { + return fake.RequireCurrentUserStub() } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.requireCurrentUserReturns return fakeReturns.result1, fakeReturns.result2 } @@ -360,16 +355,15 @@ func (fake *FakeSharedActor) RequireTargetedOrg() (string, error) { ret, specificReturn := fake.requireTargetedOrgReturnsOnCall[len(fake.requireTargetedOrgArgsForCall)] fake.requireTargetedOrgArgsForCall = append(fake.requireTargetedOrgArgsForCall, struct { }{}) - stub := fake.RequireTargetedOrgStub - fakeReturns := fake.requireTargetedOrgReturns fake.recordInvocation("RequireTargetedOrg", []interface{}{}) fake.requireTargetedOrgMutex.Unlock() - if stub != nil { - return stub() + if fake.RequireTargetedOrgStub != nil { + return fake.RequireTargetedOrgStub() } if specificReturn { return ret.result1, ret.result2 } + fakeReturns := fake.requireTargetedOrgReturns return fakeReturns.result1, fakeReturns.result2 } diff --git a/command/config.go b/command/config.go index 7aec299c670..44b30e5ba99 100644 --- a/command/config.go +++ b/command/config.go @@ -80,4 +80,6 @@ type Config interface { Verbose() (bool, []string) WritePluginConfig() error WriteConfig() error + IsCFOnK8s() bool + SetKubernetesAuthInfo(authInfo string) } diff --git a/command/translatableerror/not_supported_on_k8s_error.go b/command/translatableerror/not_supported_on_k8s_error.go new file mode 100644 index 00000000000..630edef1271 --- /dev/null +++ b/command/translatableerror/not_supported_on_k8s_error.go @@ -0,0 +1,19 @@ +package translatableerror + +// NotSupportedOnKubernetesArgumentError represents an error caused by using an +// argument that is not supported on kubernetes +type NotSupportedOnKubernetesArgumentError struct { + Arg string +} + +func (NotSupportedOnKubernetesArgumentError) DisplayUsage() {} + +func (NotSupportedOnKubernetesArgumentError) Error() string { + return "The argument {{.Arg}} is not supported on Kubernetes" +} + +func (e NotSupportedOnKubernetesArgumentError) Translate(translate func(string, ...interface{}) string) string { + return translate(e.Error(), map[string]interface{}{ + "Arg": e.Arg, + }) +} diff --git a/command/v7/actor.go b/command/v7/actor.go index 52fc12ece70..d8bc2a17dca 100644 --- a/command/v7/actor.go +++ b/command/v7/actor.go @@ -14,6 +14,7 @@ import ( "code.cloudfoundry.org/cli/cf/configuration/coreconfig" "code.cloudfoundry.org/cli/resources" "code.cloudfoundry.org/cli/types" + "code.cloudfoundry.org/cli/util/configv3" "github.com/SermoDigital/jose/jwt" ) @@ -99,6 +100,7 @@ type Actor interface { GetApplicationsByNamesAndSpace(appNames []string, spaceGUID string) ([]resources.Application, v7action.Warnings, error) GetBuildpackLabels(buildpackName string, buildpackStack string) (map[string]types.NullString, v7action.Warnings, error) GetBuildpacks(labelSelector string) ([]resources.Buildpack, v7action.Warnings, error) + GetCurrentUser() (configv3.User, error) GetDefaultDomain(orgGUID string) (resources.Domain, v7action.Warnings, error) GetDetailedAppSummary(appName string, spaceGUID string, withObfuscatedValues bool) (v7action.DetailedApplicationSummary, v7action.Warnings, error) GetDomain(domainGUID string) (resources.Domain, v7action.Warnings, error) diff --git a/command/v7/add_network_policy_command.go b/command/v7/add_network_policy_command.go index 1af831be9ad..b795bde454a 100644 --- a/command/v7/add_network_policy_command.go +++ b/command/v7/add_network_policy_command.go @@ -98,7 +98,7 @@ func (cmd AddNetworkPolicyCommand) Execute(args []string) error { destSpaceGUID = destSpace.GUID } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/add_network_policy_command_test.go b/command/v7/add_network_policy_command_test.go index e046bdfd05a..998afb510c9 100644 --- a/command/v7/add_network_policy_command_test.go +++ b/command/v7/add_network_policy_command_test.go @@ -88,7 +88,7 @@ var _ = Describe("add-network-policy Command", func() { When("the user is logged in, an org is targeted, and a space is targeted", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "some-space", GUID: "some-space-guid"}) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org"}) }) diff --git a/command/v7/allow_space_ssh_command.go b/command/v7/allow_space_ssh_command.go index 3900e532600..38e6f99e56b 100644 --- a/command/v7/allow_space_ssh_command.go +++ b/command/v7/allow_space_ssh_command.go @@ -14,13 +14,12 @@ type AllowSpaceSSHCommand struct { } func (cmd *AllowSpaceSSHCommand) Execute(args []string) error { - err := cmd.SharedActor.CheckTarget(true, false) if err != nil { return err } - currentUserName, err := cmd.Config.CurrentUserName() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } @@ -30,7 +29,7 @@ func (cmd *AllowSpaceSSHCommand) Execute(args []string) error { cmd.UI.DisplayTextWithFlavor("Enabling ssh support for space {{.Space}} as {{.CurrentUserName}}...", map[string]interface{}{ "Space": inputSpace, - "CurrentUserName": currentUserName, + "CurrentUserName": currentUser.Name, }) warnings, err := cmd.Actor.UpdateSpaceFeature(inputSpace, targetedOrgGUID, true, "ssh") @@ -50,5 +49,4 @@ func (cmd *AllowSpaceSSHCommand) Execute(args []string) error { cmd.UI.DisplayOK() return err - } diff --git a/command/v7/allow_space_ssh_command_test.go b/command/v7/allow_space_ssh_command_test.go index de3d1553c6b..b8697fa1d1c 100644 --- a/command/v7/allow_space_ssh_command_test.go +++ b/command/v7/allow_space_ssh_command_test.go @@ -8,6 +8,7 @@ import ( "code.cloudfoundry.org/cli/command/commandfakes" . "code.cloudfoundry.org/cli/command/v7" "code.cloudfoundry.org/cli/command/v7/v7fakes" + "code.cloudfoundry.org/cli/util/configv3" "code.cloudfoundry.org/cli/util/ui" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -47,7 +48,7 @@ var _ = Describe("allow-space-ssh Command", func() { binaryName = "faceman" fakeConfig.BinaryNameReturns(binaryName) currentUserName = "some-user" - fakeConfig.CurrentUserNameReturns(currentUserName, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: currentUserName}, nil) }) JustBeforeEach(func() { @@ -71,7 +72,7 @@ var _ = Describe("allow-space-ssh Command", func() { When("checking the current user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("", errors.New("uh oh")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("uh oh")) }) It("returns the error", func() { diff --git a/command/v7/api_command.go b/command/v7/api_command.go index aa222af4c96..5127b33bbf5 100644 --- a/command/v7/api_command.go +++ b/command/v7/api_command.go @@ -26,7 +26,7 @@ func (cmd *APICommand) Setup(config command.Config, ui command.UI) error { cmd.UI = ui cmd.Config = config - ccClient, _ := shared.NewWrappedCloudControllerClient(config, ui) + ccClient := shared.NewWrappedCloudControllerClient(config, ui) cmd.Actor = v7action.NewActor(ccClient, config, nil, nil, nil, clock.NewClock()) return nil } diff --git a/command/v7/api_command_test.go b/command/v7/api_command_test.go index 66fad029a24..a69afda6996 100644 --- a/command/v7/api_command_test.go +++ b/command/v7/api_command_test.go @@ -144,9 +144,7 @@ API version: 100.200.300`, }) When("the URL host does not exist", func() { - var ( - requestErr ccerror.RequestError - ) + var requestErr ccerror.RequestError BeforeEach(func() { CCAPI = "i.do.not.exist.com" diff --git a/command/v7/app_command.go b/command/v7/app_command.go index 9c7227dc195..d431a71ff55 100644 --- a/command/v7/app_command.go +++ b/command/v7/app_command.go @@ -24,7 +24,7 @@ func (cmd AppCommand) Execute(args []string) error { return cmd.displayAppGUID() } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/app_command_test.go b/command/v7/app_command_test.go index 784fd423367..238376ba7b7 100644 --- a/command/v7/app_command_test.go +++ b/command/v7/app_command_test.go @@ -60,7 +60,7 @@ var _ = Describe("app Command", func() { GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { @@ -87,7 +87,7 @@ var _ = Describe("app Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/apply_manifest_command.go b/command/v7/apply_manifest_command.go index 86ae5c0f55a..5f959382f51 100644 --- a/command/v7/apply_manifest_command.go +++ b/command/v7/apply_manifest_command.go @@ -50,7 +50,7 @@ func (cmd ApplyManifestCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/apply_manifest_command_test.go b/command/v7/apply_manifest_command_test.go index ff940a22532..bc29e3c54e1 100644 --- a/command/v7/apply_manifest_command_test.go +++ b/command/v7/apply_manifest_command_test.go @@ -88,7 +88,7 @@ var _ = Describe("apply-manifest Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { @@ -109,7 +109,7 @@ var _ = Describe("apply-manifest Command", func() { Name: "some-space", GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) When("the manifest location is specified with `-f`", func() { diff --git a/command/v7/apps_command.go b/command/v7/apps_command.go index f0ca3ab6748..e25ad73f5be 100644 --- a/command/v7/apps_command.go +++ b/command/v7/apps_command.go @@ -22,7 +22,7 @@ func (cmd AppsCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/apps_command_test.go b/command/v7/apps_command_test.go index a9307cd8c34..4da0afec7da 100644 --- a/command/v7/apps_command_test.go +++ b/command/v7/apps_command_test.go @@ -56,7 +56,7 @@ var _ = Describe("apps Command", func() { GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { @@ -87,7 +87,7 @@ var _ = Describe("apps Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/bind_route_service_command.go b/command/v7/bind_route_service_command.go index 6bffdf3cbe8..b6e0b2fa867 100644 --- a/command/v7/bind_route_service_command.go +++ b/command/v7/bind_route_service_command.go @@ -76,7 +76,7 @@ In Windows Command Line use single-quoted, escaped JSON: '{\"valid\":\"json\"}' } func (cmd BindRouteServiceCommand) displayIntro() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/bind_route_service_command_test.go b/command/v7/bind_route_service_command_test.go index b9925caebfb..537c529843a 100644 --- a/command/v7/bind_route_service_command_test.go +++ b/command/v7/bind_route_service_command_test.go @@ -60,7 +60,7 @@ var _ = Describe("bind-route-service Command", func() { fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: fakeOrgName}) - fakeConfig.CurrentUserReturns(configv3.User{Name: fakeUserName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: fakeUserName}, nil) fakeActor.CreateRouteBindingReturns( nil, @@ -346,7 +346,7 @@ var _ = Describe("bind-route-service Command", func() { When("getting the username returns an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("bad thing")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("bad thing")) }) It("returns the error", func() { diff --git a/command/v7/bind_running_security_group_command.go b/command/v7/bind_running_security_group_command.go index 6997a5d1323..82aca45eb39 100644 --- a/command/v7/bind_running_security_group_command.go +++ b/command/v7/bind_running_security_group_command.go @@ -21,7 +21,7 @@ func (cmd BindRunningSecurityGroupCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/bind_running_security_group_command_test.go b/command/v7/bind_running_security_group_command_test.go index 02460926392..c993a862412 100644 --- a/command/v7/bind_running_security_group_command_test.go +++ b/command/v7/bind_running_security_group_command_test.go @@ -47,7 +47,7 @@ var _ = Describe("bind-running-security-group Command", func() { binaryName = "faceman" fakeConfig.BinaryNameReturns(binaryName) - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) @@ -63,7 +63,7 @@ var _ = Describe("bind-running-security-group Command", func() { When("the current user is invalid", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{}, errors.New("some-error")) }) diff --git a/command/v7/bind_security_group_command.go b/command/v7/bind_security_group_command.go index 154d451ed27..712eedfd7ca 100644 --- a/command/v7/bind_security_group_command.go +++ b/command/v7/bind_security_group_command.go @@ -27,7 +27,7 @@ func (cmd BindSecurityGroupCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/bind_security_group_command_test.go b/command/v7/bind_security_group_command_test.go index c8acfadf0ae..b90fa78d797 100644 --- a/command/v7/bind_security_group_command_test.go +++ b/command/v7/bind_security_group_command_test.go @@ -53,7 +53,7 @@ var _ = Describe("bind-security-group Command", func() { cmd.RequiredArgs.SecurityGroupName = "some-security-group" cmd.RequiredArgs.OrganizationName = "some-org" - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) fakeActor.GetSecurityGroupReturns( @@ -95,7 +95,7 @@ var _ = Describe("bind-security-group Command", func() { BeforeEach(func() { expectedErr = errors.New("getting current user error") - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{}, expectedErr) }) diff --git a/command/v7/bind_service_command.go b/command/v7/bind_service_command.go index 55c5512f23c..4f4f9e480a9 100644 --- a/command/v7/bind_service_command.go +++ b/command/v7/bind_service_command.go @@ -101,7 +101,7 @@ CF_NAME bind-service myapp mydb -c ~/workspace/tmp/instance_config.json --bindin } func (cmd BindServiceCommand) displayIntro() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/bind_service_command_test.go b/command/v7/bind_service_command_test.go index e2ec55dac4c..f38481905dc 100644 --- a/command/v7/bind_service_command_test.go +++ b/command/v7/bind_service_command_test.go @@ -58,7 +58,7 @@ var _ = Describe("bind-service Command", func() { fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: fakeOrgName}) - fakeConfig.CurrentUserReturns(configv3.User{Name: fakeUserName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: fakeUserName}, nil) fakeActor.CreateServiceAppBindingReturns( nil, @@ -323,7 +323,7 @@ var _ = Describe("bind-service Command", func() { When("getting the username returns an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("bad thing")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("bad thing")) }) It("returns the error", func() { diff --git a/command/v7/bind_staging_security_group_command.go b/command/v7/bind_staging_security_group_command.go index ae637a4ce25..306c0548d0c 100644 --- a/command/v7/bind_staging_security_group_command.go +++ b/command/v7/bind_staging_security_group_command.go @@ -21,7 +21,7 @@ func (cmd BindStagingSecurityGroupCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/bind_staging_security_group_command_test.go b/command/v7/bind_staging_security_group_command_test.go index 09fc76fe7c0..c7069f91b7a 100644 --- a/command/v7/bind_staging_security_group_command_test.go +++ b/command/v7/bind_staging_security_group_command_test.go @@ -47,7 +47,7 @@ var _ = Describe("bind-staging-security-group Command", func() { binaryName = "faceman" fakeConfig.BinaryNameReturns(binaryName) - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) @@ -63,7 +63,7 @@ var _ = Describe("bind-staging-security-group Command", func() { When("the current user is invalid", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{}, errors.New("some-error")) }) diff --git a/command/v7/buildpacks_command.go b/command/v7/buildpacks_command.go index 8a8533fd06e..d0726abb496 100644 --- a/command/v7/buildpacks_command.go +++ b/command/v7/buildpacks_command.go @@ -21,7 +21,7 @@ func (cmd BuildpacksCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/buildpacks_command_test.go b/command/v7/buildpacks_command_test.go index 04f6b35ee89..6dd304e0686 100644 --- a/command/v7/buildpacks_command_test.go +++ b/command/v7/buildpacks_command_test.go @@ -72,7 +72,7 @@ var _ = Describe("buildpacks Command", func() { When("the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "apple"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "apple"}, nil) }) It("should print text indicating its runnning", func() { diff --git a/command/v7/cancel_deployment_command.go b/command/v7/cancel_deployment_command.go index c89296eae12..55998b32a4c 100644 --- a/command/v7/cancel_deployment_command.go +++ b/command/v7/cancel_deployment_command.go @@ -18,7 +18,7 @@ func (cmd *CancelDeploymentCommand) Execute(args []string) error { return err } - userName, err := cmd.Config.CurrentUserName() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } @@ -29,7 +29,7 @@ func (cmd *CancelDeploymentCommand) Execute(args []string) error { "AppName": cmd.RequiredArgs.AppName, "OrgName": cmd.Config.TargetedOrganization().Name, "SpaceName": cmd.Config.TargetedSpace().Name, - "UserName": userName, + "UserName": user.Name, }, ) diff --git a/command/v7/cancel_deployment_command_test.go b/command/v7/cancel_deployment_command_test.go index 0653058f6e1..ce597a138b2 100644 --- a/command/v7/cancel_deployment_command_test.go +++ b/command/v7/cancel_deployment_command_test.go @@ -63,7 +63,7 @@ var _ = Describe("Cancel deployment command", func() { GUID: spaceGUID, }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "timmyD"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "timmyD"}, nil) }) JustBeforeEach(func() { @@ -90,7 +90,7 @@ var _ = Describe("Cancel deployment command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserNameReturns("", expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/check_route_command.go b/command/v7/check_route_command.go index 2649bae98d0..444cd1f4d25 100644 --- a/command/v7/check_route_command.go +++ b/command/v7/check_route_command.go @@ -37,7 +37,7 @@ func (cmd CheckRouteCommand) Execute(args []string) error { return err } - _, err = cmd.Config.CurrentUser() + _, err = cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/check_route_command_test.go b/command/v7/check_route_command_test.go index d529be0b960..548dd7e28a3 100644 --- a/command/v7/check_route_command_test.go +++ b/command/v7/check_route_command_test.go @@ -47,7 +47,7 @@ var _ = Describe("check-route Command", func() { fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "some-space", GUID: "some-space-guid"}) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org"}) - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeActor.CheckRouteReturns( true, v7action.Warnings{"check-route-warning"}, @@ -77,12 +77,12 @@ var _ = Describe("check-route Command", func() { }) It("checks if the user is logged in", func() { - Expect(fakeConfig.CurrentUserCallCount()).To(Equal(1)) + Expect(fakeActor.GetCurrentUserCallCount()).To(Equal(1)) }) When("the user is not logged in", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("no current user")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("no current user")) }) It("returns an error", func() { diff --git a/command/v7/copy_source_command.go b/command/v7/copy_source_command.go index 8ee79fe91b0..42f869b2458 100644 --- a/command/v7/copy_source_command.go +++ b/command/v7/copy_source_command.go @@ -67,7 +67,7 @@ func (cmd CopySourceCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/copy_source_command_test.go b/command/v7/copy_source_command_test.go index 7d4af8fa7c3..3b8cedb9c04 100644 --- a/command/v7/copy_source_command_test.go +++ b/command/v7/copy_source_command_test.go @@ -72,7 +72,7 @@ var _ = Describe("copy-source Command", func() { fakeConfig.BinaryNameReturns(binaryName) fakeSharedActor.CheckTargetReturns(nil) - fakeConfig.CurrentUserReturns(configv3.User{Name: userName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: userName}, nil) fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "some-space", GUID: "some-space-guid"}) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org"}) @@ -112,12 +112,12 @@ var _ = Describe("copy-source Command", func() { }) It("retrieves the current user", func() { - Expect(fakeConfig.CurrentUserCallCount()).To(Equal(1)) + Expect(fakeActor.GetCurrentUserCallCount()).To(Equal(1)) }) When("retrieving the current user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("not-logged-in")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("not-logged-in")) }) It("returns an error", func() { diff --git a/command/v7/create_app_command.go b/command/v7/create_app_command.go index 4d250626605..938be0bcf73 100644 --- a/command/v7/create_app_command.go +++ b/command/v7/create_app_command.go @@ -22,7 +22,7 @@ func (cmd CreateAppCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/create_app_command_test.go b/command/v7/create_app_command_test.go index c53faa93895..d4b416a7492 100644 --- a/command/v7/create_app_command_test.go +++ b/command/v7/create_app_command_test.go @@ -78,7 +78,7 @@ var _ = Describe("create-app Command", func() { When("the user is logged in", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "some-space", GUID: "some-space-guid"}) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org"}) }) diff --git a/command/v7/create_app_manifest_command.go b/command/v7/create_app_manifest_command.go index ab824c73c57..69d8652b50b 100644 --- a/command/v7/create_app_manifest_command.go +++ b/command/v7/create_app_manifest_command.go @@ -39,7 +39,7 @@ func (cmd CreateAppManifestCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/create_app_manifest_command_test.go b/command/v7/create_app_manifest_command_test.go index 65ac1a1904f..23894166f13 100644 --- a/command/v7/create_app_manifest_command_test.go +++ b/command/v7/create_app_manifest_command_test.go @@ -79,7 +79,7 @@ var _ = Describe("create-app-manifest Command", func() { fakeConfig.TargetedSpaceReturns(configv3.Space{ GUID: "some-space-guid", Name: "some-space"}) - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) diff --git a/command/v7/create_buildpack_command.go b/command/v7/create_buildpack_command.go index 4a0dcb2e857..526fdc83474 100644 --- a/command/v7/create_buildpack_command.go +++ b/command/v7/create_buildpack_command.go @@ -37,7 +37,7 @@ func (cmd CreateBuildpackCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/create_buildpack_command_test.go b/command/v7/create_buildpack_command_test.go index 374772da8a5..43b96f17a3f 100644 --- a/command/v7/create_buildpack_command_test.go +++ b/command/v7/create_buildpack_command_test.go @@ -84,7 +84,7 @@ var _ = Describe("create buildpack Command", func() { When("the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "the-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "the-user"}, nil) }) It("should print text indicating it is creating a buildpack", func() { diff --git a/command/v7/create_isolation_segment_command.go b/command/v7/create_isolation_segment_command.go index a170740eabe..04026ec5edf 100644 --- a/command/v7/create_isolation_segment_command.go +++ b/command/v7/create_isolation_segment_command.go @@ -19,7 +19,7 @@ func (cmd CreateIsolationSegmentCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/create_isolation_segment_command_test.go b/command/v7/create_isolation_segment_command_test.go index 66112a628f6..1654035701d 100644 --- a/command/v7/create_isolation_segment_command_test.go +++ b/command/v7/create_isolation_segment_command_test.go @@ -69,7 +69,7 @@ var _ = Describe("create-isolation-segment Command", func() { When("the user is logged in", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) cmd.RequiredArgs.IsolationSegmentName = isolationSegment }) diff --git a/command/v7/create_org_command.go b/command/v7/create_org_command.go index a7ca4c30a6d..f28156bac8f 100644 --- a/command/v7/create_org_command.go +++ b/command/v7/create_org_command.go @@ -20,7 +20,7 @@ func (cmd CreateOrgCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/create_org_command_test.go b/command/v7/create_org_command_test.go index 3c19d346c79..e710b03fe42 100644 --- a/command/v7/create_org_command_test.go +++ b/command/v7/create_org_command_test.go @@ -45,7 +45,7 @@ var _ = Describe("create-org Command", func() { fakeConfig.BinaryNameReturns(binaryName) orgName = "some-org" currentUsername = "bob" - fakeConfig.CurrentUserReturns(configv3.User{Name: currentUsername}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: currentUsername}, nil) quotaName = "quota-name" cmd = v7.CreateOrgCommand{ diff --git a/command/v7/create_org_quota_command.go b/command/v7/create_org_quota_command.go index 6f9bfa78ae1..fe34a1de228 100644 --- a/command/v7/create_org_quota_command.go +++ b/command/v7/create_org_quota_command.go @@ -28,7 +28,7 @@ func (cmd CreateOrgQuotaCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/create_org_quota_command_test.go b/command/v7/create_org_quota_command_test.go index e1fe74f5d1d..d8f66f51fdd 100644 --- a/command/v7/create_org_quota_command_test.go +++ b/command/v7/create_org_quota_command_test.go @@ -48,7 +48,7 @@ var _ = Describe("create-org-quota Command", func() { } currentUserName = "bob" - fakeConfig.CurrentUserReturns(configv3.User{Name: currentUserName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: currentUserName}, nil) }) JustBeforeEach(func() { diff --git a/command/v7/create_package_command.go b/command/v7/create_package_command.go index 3febb4f3421..47f6d2ff284 100644 --- a/command/v7/create_package_command.go +++ b/command/v7/create_package_command.go @@ -39,7 +39,11 @@ func (cmd CreatePackageCommand) Execute(args []string) error { } isDockerImage := (cmd.DockerImage.Path != "") - err = cmd.PackageDisplayer.DisplaySetupMessage(cmd.RequiredArgs.AppName, isDockerImage) + user, err := cmd.Actor.GetCurrentUser() + if err != nil { + return err + } + err = cmd.PackageDisplayer.DisplaySetupMessage(cmd.RequiredArgs.AppName, user.Name, isDockerImage) if err != nil { return err } diff --git a/command/v7/create_package_command_test.go b/command/v7/create_package_command_test.go index f89c2a2b621..24dabe17479 100644 --- a/command/v7/create_package_command_test.go +++ b/command/v7/create_package_command_test.go @@ -83,7 +83,7 @@ var _ = Describe("create-package Command", func() { When("the user is logged in", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "some-space", GUID: "some-space-guid"}) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org"}) }) diff --git a/command/v7/create_private_domain_command.go b/command/v7/create_private_domain_command.go index 6727fde8a86..a0cbe7b4818 100644 --- a/command/v7/create_private_domain_command.go +++ b/command/v7/create_private_domain_command.go @@ -18,7 +18,7 @@ func (cmd CreatePrivateDomainCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/create_private_domain_command_test.go b/command/v7/create_private_domain_command_test.go index 8363c569f90..68f2fd6448d 100644 --- a/command/v7/create_private_domain_command_test.go +++ b/command/v7/create_private_domain_command_test.go @@ -78,7 +78,7 @@ var _ = Describe("create-private-domain Command", func() { When("the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "the-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "the-user"}, nil) }) It("should print text indicating it is creating a domain", func() { diff --git a/command/v7/create_route_command.go b/command/v7/create_route_command.go index 654bfb0fcc0..7d6fc07e6bd 100644 --- a/command/v7/create_route_command.go +++ b/command/v7/create_route_command.go @@ -24,7 +24,7 @@ func (cmd CreateRouteCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/create_route_command_test.go b/command/v7/create_route_command_test.go index ab9235bb432..b53f14758d9 100644 --- a/command/v7/create_route_command_test.go +++ b/command/v7/create_route_command_test.go @@ -92,7 +92,7 @@ var _ = Describe("create-route Command", func() { When("the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "the-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "the-user"}, nil) fakeConfig.TargetedSpaceReturns(configv3.Space{ Name: spaceName, GUID: spaceGUID, diff --git a/command/v7/create_security_group_command.go b/command/v7/create_security_group_command.go index 420cde2c061..7c1f29c4b76 100644 --- a/command/v7/create_security_group_command.go +++ b/command/v7/create_security_group_command.go @@ -22,7 +22,7 @@ func (cmd CreateSecurityGroupCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/create_security_group_command_test.go b/command/v7/create_security_group_command_test.go index 6f0c22d9da0..51b23f27e4b 100644 --- a/command/v7/create_security_group_command_test.go +++ b/command/v7/create_security_group_command_test.go @@ -56,7 +56,7 @@ var _ = Describe("create-security-group Command", func() { } fakeConfig.HasTargetedOrganizationReturns(false) fakeConfig.HasTargetedSpaceReturns(false) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { diff --git a/command/v7/create_service_broker_command.go b/command/v7/create_service_broker_command.go index 99c2d224c6d..0fbd44c5f69 100644 --- a/command/v7/create_service_broker_command.go +++ b/command/v7/create_service_broker_command.go @@ -21,7 +21,7 @@ func (cmd *CreateServiceBrokerCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/create_service_broker_command_test.go b/command/v7/create_service_broker_command_test.go index 6cc91f4ea52..f19175c3779 100644 --- a/command/v7/create_service_broker_command_test.go +++ b/command/v7/create_service_broker_command_test.go @@ -65,7 +65,7 @@ var _ = Describe("create-service-broker Command", func() { When("fetching the current user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("an error occurred")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("an error occurred")) }) It("return an error", func() { @@ -75,7 +75,7 @@ var _ = Describe("create-service-broker Command", func() { When("fetching the current user succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) It("checks that there is a valid target", func() { diff --git a/command/v7/create_service_command.go b/command/v7/create_service_command.go index 1a60195e9ac..ee10e723bba 100644 --- a/command/v7/create_service_command.go +++ b/command/v7/create_service_command.go @@ -110,7 +110,7 @@ func (cmd CreateServiceCommand) Execute(args []string) error { } func (cmd CreateServiceCommand) displayCreatingMessage() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/create_service_command_test.go b/command/v7/create_service_command_test.go index 2e291c9f932..1deddb8d440 100644 --- a/command/v7/create_service_command_test.go +++ b/command/v7/create_service_command_test.go @@ -90,7 +90,7 @@ var _ = Describe("create-service Command", func() { Name: fakeOrgName, }) - fakeConfig.CurrentUserReturns(configv3.User{Name: fakeUserName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: fakeUserName}, nil) }) It("calls the actor with the right arguments", func() { @@ -292,7 +292,7 @@ var _ = Describe("create-service Command", func() { When("getting the user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: fakeUserName}, errors.New("boom")) + fakeActor.GetCurrentUserReturns(configv3.User{Name: fakeUserName}, errors.New("boom")) }) It("returns the error", func() { diff --git a/command/v7/create_service_key_command.go b/command/v7/create_service_key_command.go index 6d8987c8ff3..34bfba0542d 100644 --- a/command/v7/create_service_key_command.go +++ b/command/v7/create_service_key_command.go @@ -81,7 +81,7 @@ CF_NAME create-service-key mydb mykey -c ~/workspace/tmp/instance_config.json } func (cmd CreateServiceKeyCommand) displayIntro() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/create_service_key_command_test.go b/command/v7/create_service_key_command_test.go index 74e4541bf18..83363defefa 100644 --- a/command/v7/create_service_key_command_test.go +++ b/command/v7/create_service_key_command_test.go @@ -49,7 +49,7 @@ var _ = Describe("create-service-key Command", func() { } fakeConfig.TargetedSpaceReturns(configv3.Space{GUID: fakeSpaceGUID}) - fakeConfig.CurrentUserReturns(configv3.User{Name: fakeUserName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: fakeUserName}, nil) fakeActor.CreateServiceKeyReturns( nil, @@ -292,7 +292,7 @@ var _ = Describe("create-service-key Command", func() { When("getting the username returns an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("bad thing")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("bad thing")) }) It("returns the error", func() { diff --git a/command/v7/create_shared_domain_command.go b/command/v7/create_shared_domain_command.go index 39237843927..feb9940e213 100644 --- a/command/v7/create_shared_domain_command.go +++ b/command/v7/create_shared_domain_command.go @@ -20,7 +20,7 @@ func (cmd CreateSharedDomainCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/create_shared_domain_command_test.go b/command/v7/create_shared_domain_command_test.go index b042d80cf11..9484348694d 100644 --- a/command/v7/create_shared_domain_command_test.go +++ b/command/v7/create_shared_domain_command_test.go @@ -76,7 +76,7 @@ var _ = Describe("create-shared-domain Command", func() { When("the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "the-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "the-user"}, nil) }) It("should print text indicating it is creating a domain", func() { diff --git a/command/v7/create_space_command.go b/command/v7/create_space_command.go index 376cb5d0144..dd8b85dd7ba 100644 --- a/command/v7/create_space_command.go +++ b/command/v7/create_space_command.go @@ -31,9 +31,7 @@ func (cmd CreateSpaceCommand) Execute(args []string) error { return err } - var ( - orgName, orgGUID string - ) + var orgName, orgGUID string if cmd.Organization == "" { _, err = cmd.SharedActor.RequireTargetedOrg() @@ -52,7 +50,7 @@ func (cmd CreateSpaceCommand) Execute(args []string) error { orgGUID = org.GUID } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/create_space_command_test.go b/command/v7/create_space_command_test.go index 1ce148cf5c4..d11c05f044f 100644 --- a/command/v7/create_space_command_test.go +++ b/command/v7/create_space_command_test.go @@ -55,7 +55,7 @@ var _ = Describe("create-space Command", func() { Name: "some-org-name", GUID: "some-org-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{ + fakeActor.GetCurrentUserReturns(configv3.User{ Name: userName, Origin: "some-user-origin", }, nil) diff --git a/command/v7/create_space_quota_command.go b/command/v7/create_space_quota_command.go index afc5eb2e7d3..892d04675e7 100644 --- a/command/v7/create_space_quota_command.go +++ b/command/v7/create_space_quota_command.go @@ -27,7 +27,7 @@ func (cmd CreateSpaceQuotaCommand) Execute([]string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/create_space_quota_command_test.go b/command/v7/create_space_quota_command_test.go index 6e0894673da..6e94f2cb402 100644 --- a/command/v7/create_space_quota_command_test.go +++ b/command/v7/create_space_quota_command_test.go @@ -79,7 +79,7 @@ var _ = Describe("create-space-quota Command", func() { Name: "some-org-name", GUID: "some-org-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{ + fakeActor.GetCurrentUserReturns(configv3.User{ Name: userName, Origin: "some-user-origin", }, nil) diff --git a/command/v7/create_user_provided_service_command.go b/command/v7/create_user_provided_service_command.go index bf3bf04e00e..c0cc5e5083b 100644 --- a/command/v7/create_user_provided_service_command.go +++ b/command/v7/create_user_provided_service_command.go @@ -52,7 +52,7 @@ func (cmd CreateUserProvidedServiceCommand) Execute(args []string) error { } func (cmd CreateUserProvidedServiceCommand) displayMessage() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/create_user_provided_service_command_test.go b/command/v7/create_user_provided_service_command_test.go index 9f508b9367e..805649e3942 100644 --- a/command/v7/create_user_provided_service_command_test.go +++ b/command/v7/create_user_provided_service_command_test.go @@ -86,7 +86,7 @@ var _ = Describe("create-user-provided-service Command", func() { Name: fakeOrgName, }) - fakeConfig.CurrentUserReturns(configv3.User{Name: fakeUserName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: fakeUserName}, nil) setPositionalFlags(&cmd, fakeServiceInstanceName) @@ -188,7 +188,7 @@ var _ = Describe("create-user-provided-service Command", func() { When("getting the user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: fakeUserName}, errors.New("boom")) + fakeActor.GetCurrentUserReturns(configv3.User{Name: fakeUserName}, errors.New("boom")) }) It("returns the error", func() { diff --git a/command/v7/delete_command.go b/command/v7/delete_command.go index b45abf764bf..23edea0b683 100644 --- a/command/v7/delete_command.go +++ b/command/v7/delete_command.go @@ -21,7 +21,7 @@ func (cmd DeleteCommand) Execute(args []string) error { return err } - currentUser, err := cmd.Config.CurrentUser() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/delete_command_test.go b/command/v7/delete_command_test.go index d67c273e3ce..880f2629aa3 100644 --- a/command/v7/delete_command_test.go +++ b/command/v7/delete_command_test.go @@ -61,7 +61,7 @@ var _ = Describe("delete Command", func() { GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { @@ -132,7 +132,7 @@ var _ = Describe("delete Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/delete_isolation_segment_command.go b/command/v7/delete_isolation_segment_command.go index 6e586ca6c3a..4858cf110f3 100644 --- a/command/v7/delete_isolation_segment_command.go +++ b/command/v7/delete_isolation_segment_command.go @@ -35,7 +35,7 @@ func (cmd DeleteIsolationSegmentCommand) Execute(args []string) error { } } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/delete_isolation_segment_command_test.go b/command/v7/delete_isolation_segment_command_test.go index 82382680858..32f5d672085 100644 --- a/command/v7/delete_isolation_segment_command_test.go +++ b/command/v7/delete_isolation_segment_command_test.go @@ -70,7 +70,7 @@ var _ = Describe("delete-isolation-segment Command", func() { When("the user is logged in", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) cmd.RequiredArgs.IsolationSegmentName = isolationSegment }) diff --git a/command/v7/delete_org_command.go b/command/v7/delete_org_command.go index 4131654ea90..33c38d99a11 100644 --- a/command/v7/delete_org_command.go +++ b/command/v7/delete_org_command.go @@ -20,7 +20,7 @@ func (cmd *DeleteOrgCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/delete_org_command_test.go b/command/v7/delete_org_command_test.go index 38bf89cc523..8895d0c15fc 100644 --- a/command/v7/delete_org_command_test.go +++ b/command/v7/delete_org_command_test.go @@ -78,7 +78,7 @@ var _ = Describe("delete-org Command", func() { BeforeEach(func() { returnedErr = errors.New("some error") - fakeConfig.CurrentUserReturns(configv3.User{}, returnedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, returnedErr) }) It("returns the error", func() { @@ -88,7 +88,7 @@ var _ = Describe("delete-org Command", func() { When("getting the current user does not return an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) diff --git a/command/v7/delete_org_quota_command.go b/command/v7/delete_org_quota_command.go index 3df1937cfb4..b3199feb326 100644 --- a/command/v7/delete_org_quota_command.go +++ b/command/v7/delete_org_quota_command.go @@ -20,7 +20,7 @@ func (cmd DeleteOrgQuotaCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/delete_org_quota_command_test.go b/command/v7/delete_org_quota_command_test.go index 466c39b8e0f..b160cad6920 100644 --- a/command/v7/delete_org_quota_command_test.go +++ b/command/v7/delete_org_quota_command_test.go @@ -37,7 +37,7 @@ var _ = Describe("delete-org-quota Command", func() { binaryName = "faceman" fakeConfig.BinaryNameReturns(binaryName) - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) cmd = DeleteOrgQuotaCommand{ BaseCommand: BaseCommand{ diff --git a/command/v7/delete_orphaned_routes_command.go b/command/v7/delete_orphaned_routes_command.go index f8bb427b4e0..3e006d9e630 100644 --- a/command/v7/delete_orphaned_routes_command.go +++ b/command/v7/delete_orphaned_routes_command.go @@ -14,7 +14,7 @@ func (cmd DeleteOrphanedRoutesCommand) Execute(args []string) error { return err } - _, err = cmd.Config.CurrentUser() + _, err = cmd.Actor.GetCurrentUser() if err != nil { return err } @@ -32,7 +32,7 @@ func (cmd DeleteOrphanedRoutesCommand) Execute(args []string) error { } } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/delete_orphaned_routes_command_test.go b/command/v7/delete_orphaned_routes_command_test.go index d0b8b09f2b4..8e32faa7d0b 100644 --- a/command/v7/delete_orphaned_routes_command_test.go +++ b/command/v7/delete_orphaned_routes_command_test.go @@ -57,7 +57,7 @@ var _ = Describe("delete-orphaned-routes Command", func() { GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { @@ -99,7 +99,7 @@ var _ = Describe("delete-orphaned-routes Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { @@ -195,6 +195,5 @@ var _ = Describe("delete-orphaned-routes Command", func() { }) }) }) - }) }) diff --git a/command/v7/delete_private_domain_command.go b/command/v7/delete_private_domain_command.go index 1899ca6c378..52152a26516 100644 --- a/command/v7/delete_private_domain_command.go +++ b/command/v7/delete_private_domain_command.go @@ -23,7 +23,7 @@ func (cmd DeletePrivateDomainCommand) Execute(args []string) error { return err } - currentUser, err := cmd.Config.CurrentUser() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/delete_private_domain_command_test.go b/command/v7/delete_private_domain_command_test.go index 0e43f958159..d2bea0cffc8 100644 --- a/command/v7/delete_private_domain_command_test.go +++ b/command/v7/delete_private_domain_command_test.go @@ -58,7 +58,7 @@ var _ = Describe("delete-private-domain Command", func() { GUID: "some-org-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { @@ -85,7 +85,7 @@ var _ = Describe("delete-private-domain Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/delete_route_command.go b/command/v7/delete_route_command.go index 13614b6b1ae..9b707dc8fba 100644 --- a/command/v7/delete_route_command.go +++ b/command/v7/delete_route_command.go @@ -39,7 +39,7 @@ func (cmd DeleteRouteCommand) Execute(args []string) error { return err } - _, err = cmd.Config.CurrentUser() + _, err = cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/delete_route_command_test.go b/command/v7/delete_route_command_test.go index 653f28b324b..3180ad7f0eb 100644 --- a/command/v7/delete_route_command_test.go +++ b/command/v7/delete_route_command_test.go @@ -64,7 +64,7 @@ var _ = Describe("delete-route Command", func() { GUID: "some-org-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { @@ -91,7 +91,7 @@ var _ = Describe("delete-route Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/delete_security_group_command.go b/command/v7/delete_security_group_command.go index 2cdab62be49..cc446096cbf 100644 --- a/command/v7/delete_security_group_command.go +++ b/command/v7/delete_security_group_command.go @@ -22,7 +22,7 @@ func (cmd *DeleteSecurityGroupCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/delete_security_group_command_test.go b/command/v7/delete_security_group_command_test.go index 6bb006f2c71..4c322dff253 100644 --- a/command/v7/delete_security_group_command_test.go +++ b/command/v7/delete_security_group_command_test.go @@ -78,7 +78,7 @@ var _ = Describe("delete-security-group Command", func() { BeforeEach(func() { returnedErr = errors.New("some error") - fakeConfig.CurrentUserReturns(configv3.User{}, returnedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, returnedErr) }) It("returns the error", func() { @@ -88,7 +88,7 @@ var _ = Describe("delete-security-group Command", func() { When("getting the current user does not return an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) diff --git a/command/v7/delete_service_broker_command_test.go b/command/v7/delete_service_broker_command_test.go index e42cf285aa5..da7ab2fbc23 100644 --- a/command/v7/delete_service_broker_command_test.go +++ b/command/v7/delete_service_broker_command_test.go @@ -52,7 +52,7 @@ var _ = Describe("delete-service-broker Command", func() { setPositionalFlags(&cmd, serviceBrokerName) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { diff --git a/command/v7/delete_service_command.go b/command/v7/delete_service_command.go index aa44b8a33d7..670d5d8b34a 100644 --- a/command/v7/delete_service_command.go +++ b/command/v7/delete_service_command.go @@ -73,7 +73,7 @@ func (cmd DeleteServiceCommand) Usage() string { } func (cmd DeleteServiceCommand) displayEvent() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/delete_service_command_test.go b/command/v7/delete_service_command_test.go index 2f12f260ddb..bb8efba7fb5 100644 --- a/command/v7/delete_service_command_test.go +++ b/command/v7/delete_service_command_test.go @@ -253,7 +253,7 @@ var _ = Describe("delete-service command", func() { fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: orgName}) fakeConfig.TargetedSpaceReturns(configv3.Space{Name: spaceName, GUID: spaceGUID}) - fakeConfig.CurrentUserReturns(configv3.User{Name: username}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: username}, nil) cmd = DeleteServiceCommand{ BaseCommand: BaseCommand{ @@ -342,7 +342,7 @@ var _ = Describe("delete-service command", func() { When("getting the username fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("boom")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("boom")) confirmYes() }) diff --git a/command/v7/delete_service_key_command.go b/command/v7/delete_service_key_command.go index b114245ceda..52cec6cc8cd 100644 --- a/command/v7/delete_service_key_command.go +++ b/command/v7/delete_service_key_command.go @@ -89,7 +89,7 @@ func (cmd DeleteServiceKeyCommand) displayPrompt() (bool, error) { } func (cmd DeleteServiceKeyCommand) displayIntro() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/delete_service_key_command_test.go b/command/v7/delete_service_key_command_test.go index 72970e5a7a8..f2d3ec7c885 100644 --- a/command/v7/delete_service_key_command_test.go +++ b/command/v7/delete_service_key_command_test.go @@ -50,7 +50,7 @@ var _ = Describe("delete-service-key Command", func() { } fakeConfig.TargetedSpaceReturns(configv3.Space{GUID: fakeSpaceGUID}) - fakeConfig.CurrentUserReturns(configv3.User{Name: fakeUserName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: fakeUserName}, nil) fakeActor.DeleteServiceKeyByServiceInstanceAndNameReturns( nil, @@ -351,7 +351,7 @@ var _ = Describe("delete-service-key Command", func() { When("getting the username returns an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("bad thing")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("bad thing")) }) It("returns the error", func() { diff --git a/command/v7/delete_shared_domain_command.go b/command/v7/delete_shared_domain_command.go index e293cd7f142..f0045f6c0c8 100644 --- a/command/v7/delete_shared_domain_command.go +++ b/command/v7/delete_shared_domain_command.go @@ -22,7 +22,7 @@ func (cmd DeleteSharedDomainCommand) Execute(args []string) error { } domainName := cmd.RequiredArgs.Domain - currentUser, err := cmd.Config.CurrentUser() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/delete_shared_domain_command_test.go b/command/v7/delete_shared_domain_command_test.go index eeb0b84fcef..11bbfc3e846 100644 --- a/command/v7/delete_shared_domain_command_test.go +++ b/command/v7/delete_shared_domain_command_test.go @@ -59,7 +59,7 @@ var _ = Describe("delete-shared-domain Command", func() { GUID: "some-org-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { @@ -86,7 +86,7 @@ var _ = Describe("delete-shared-domain Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/delete_space_command.go b/command/v7/delete_space_command.go index 9652ef0e715..efc65de0e2b 100644 --- a/command/v7/delete_space_command.go +++ b/command/v7/delete_space_command.go @@ -32,7 +32,7 @@ func (cmd DeleteSpaceCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/delete_space_command_test.go b/command/v7/delete_space_command_test.go index 45afc51fe83..455e544dbe9 100644 --- a/command/v7/delete_space_command_test.go +++ b/command/v7/delete_space_command_test.go @@ -47,7 +47,7 @@ var _ = Describe("delete-space Command", func() { binaryName = "faceman" fakeConfig.BinaryNameReturns(binaryName) - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) }) JustBeforeEach(func() { @@ -96,7 +96,7 @@ var _ = Describe("delete-space Command", func() { BeforeEach(func() { returnedErr = errors.New("some error") - fakeConfig.CurrentUserReturns(configv3.User{}, returnedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, returnedErr) }) It("returns the error", func() { diff --git a/command/v7/delete_space_quota_command.go b/command/v7/delete_space_quota_command.go index 5d8ca16ba71..a12b9648a36 100644 --- a/command/v7/delete_space_quota_command.go +++ b/command/v7/delete_space_quota_command.go @@ -20,7 +20,7 @@ func (cmd DeleteSpaceQuotaCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/delete_space_quota_command_test.go b/command/v7/delete_space_quota_command_test.go index b070f097ee9..224deef5ee1 100644 --- a/command/v7/delete_space_quota_command_test.go +++ b/command/v7/delete_space_quota_command_test.go @@ -37,7 +37,7 @@ var _ = Describe("delete-space-quota Command", func() { binaryName = "faceman" fakeConfig.BinaryNameReturns(binaryName) - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org", GUID: "targeted-org-guid"}) fakeConfig.TargetedOrganizationNameReturns("some-org") diff --git a/command/v7/delete_user_command.go b/command/v7/delete_user_command.go index ff6e35b4fb6..a4ca2975918 100644 --- a/command/v7/delete_user_command.go +++ b/command/v7/delete_user_command.go @@ -37,14 +37,14 @@ func (cmd *DeleteUserCommand) Execute(args []string) error { } } - currentUser, err := cmd.Config.CurrentUserName() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } cmd.UI.DisplayTextWithFlavor("Deleting user {{.TargetUser}} as {{.CurrentUser}}...", map[string]interface{}{ "TargetUser": cmd.RequiredArgs.Username, - "CurrentUser": currentUser, + "CurrentUser": currentUser.Name, }) user, err := cmd.Actor.GetUser(cmd.RequiredArgs.Username, cmd.Origin) @@ -59,7 +59,6 @@ func (cmd *DeleteUserCommand) Execute(args []string) error { } warnings, err := cmd.Actor.DeleteUser(user.GUID) - if err != nil { return err } diff --git a/command/v7/delete_user_command_test.go b/command/v7/delete_user_command_test.go index efb29b9e6fb..247cd7bfff3 100644 --- a/command/v7/delete_user_command_test.go +++ b/command/v7/delete_user_command_test.go @@ -8,6 +8,7 @@ import ( . "code.cloudfoundry.org/cli/command/v7" "code.cloudfoundry.org/cli/command/v7/v7fakes" "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/configv3" "code.cloudfoundry.org/cli/util/ui" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -15,6 +16,8 @@ import ( ) var _ = Describe("delete-user Command", func() { + const currentUser = "bob" + var ( cmd DeleteUserCommand testUI *ui.UI @@ -24,8 +27,6 @@ var _ = Describe("delete-user Command", func() { binaryName string executeErr error input *Buffer - currentUser string - err error ) BeforeEach(func() { @@ -34,8 +35,7 @@ var _ = Describe("delete-user Command", func() { fakeConfig = new(commandfakes.FakeConfig) fakeSharedActor = new(commandfakes.FakeSharedActor) fakeActor = new(v7fakes.FakeActor) - currentUser, err = fakeConfig.CurrentUserName() - Expect(err).NotTo(HaveOccurred()) + fakeActor.GetCurrentUserReturns(configv3.User{Name: currentUser}, nil) cmd = DeleteUserCommand{ BaseCommand: BaseCommand{ diff --git a/command/v7/disable_feature_flag_command.go b/command/v7/disable_feature_flag_command.go index f6ef34fdd2f..6c3e36678ab 100644 --- a/command/v7/disable_feature_flag_command.go +++ b/command/v7/disable_feature_flag_command.go @@ -18,7 +18,7 @@ func (cmd DisableFeatureFlagCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/disable_feature_flag_command_test.go b/command/v7/disable_feature_flag_command_test.go index bb3b2feb44e..a5ec2ab340c 100644 --- a/command/v7/disable_feature_flag_command_test.go +++ b/command/v7/disable_feature_flag_command_test.go @@ -70,7 +70,7 @@ var _ = Describe("Disable Feature Flag Command", func() { When("the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "apple"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "apple"}, nil) }) It("should print text indicating its running", func() { diff --git a/command/v7/disable_org_isolation_command.go b/command/v7/disable_org_isolation_command.go index 0101c0cfeb5..a430f0ad058 100644 --- a/command/v7/disable_org_isolation_command.go +++ b/command/v7/disable_org_isolation_command.go @@ -17,7 +17,7 @@ func (cmd DisableOrgIsolationCommand) Execute(args []string) error { if err != nil { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/disable_org_isolation_command_test.go b/command/v7/disable_org_isolation_command_test.go index d5e2062e1f9..2b05b519f41 100644 --- a/command/v7/disable_org_isolation_command_test.go +++ b/command/v7/disable_org_isolation_command_test.go @@ -49,7 +49,7 @@ var _ = Describe("disable-org-isolation Command", func() { org = "org1" isolationSegment = "segment1" - fakeConfig.CurrentUserReturns(configv3.User{Name: "admin"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "admin"}, nil) cmd.RequiredArgs.OrganizationName = org cmd.RequiredArgs.IsolationSegmentName = isolationSegment @@ -79,7 +79,7 @@ var _ = Describe("disable-org-isolation Command", func() { When("user is not logged in", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("user-not-logged-in")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("user-not-logged-in")) cmd.RequiredArgs.OrganizationName = org cmd.RequiredArgs.IsolationSegmentName = isolationSegment }) diff --git a/command/v7/disable_service_access_command.go b/command/v7/disable_service_access_command.go index 910115f9755..5abd3b9359e 100644 --- a/command/v7/disable_service_access_command.go +++ b/command/v7/disable_service_access_command.go @@ -38,7 +38,7 @@ func (cmd DisableServiceAccessCommand) Execute(args []string) error { } func (cmd DisableServiceAccessCommand) displayMessage() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/disable_service_access_command_test.go b/command/v7/disable_service_access_command_test.go index 49eb0d3366b..d7c597a2820 100644 --- a/command/v7/disable_service_access_command_test.go +++ b/command/v7/disable_service_access_command_test.go @@ -58,7 +58,7 @@ var _ = Describe("disable-service-access Command", func() { "message text", func(plan, org, broker, expected string) { setPositionalFlags(&cmd, "fake-service") - fakeConfig.CurrentUserReturns(configv3.User{Name: "fake-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "fake-user"}, nil) setFlag(&cmd, "-o", org) setFlag(&cmd, "-p", plan) diff --git a/command/v7/disable_ssh_command.go b/command/v7/disable_ssh_command.go index 3cddb8b0d5f..794f0b0f36a 100644 --- a/command/v7/disable_ssh_command.go +++ b/command/v7/disable_ssh_command.go @@ -18,14 +18,14 @@ func (cmd *DisableSSHCommand) Execute(args []string) error { return err } - username, err := cmd.Config.CurrentUserName() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } cmd.UI.DisplayTextWithFlavor("Disabling ssh support for app {{.AppName}} as {{.CurrentUserName}}...", map[string]interface{}{ "AppName": cmd.RequiredArgs.AppName, - "CurrentUserName": username, + "CurrentUserName": user.Name, }) app, getAppWarnings, err := cmd.Actor.GetApplicationByNameAndSpace(cmd.RequiredArgs.AppName, cmd.Config.TargetedSpace().GUID) diff --git a/command/v7/disable_ssh_command_test.go b/command/v7/disable_ssh_command_test.go index b90a06a7bfc..b3715c66a0e 100644 --- a/command/v7/disable_ssh_command_test.go +++ b/command/v7/disable_ssh_command_test.go @@ -9,6 +9,7 @@ import ( . "code.cloudfoundry.org/cli/command/v7" "code.cloudfoundry.org/cli/command/v7/v7fakes" "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/configv3" "code.cloudfoundry.org/cli/util/ui" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -48,7 +49,7 @@ var _ = Describe("disable-ssh Command", func() { binaryName = "faceman" fakeConfig.BinaryNameReturns(binaryName) currentUserName = "some-user" - fakeConfig.CurrentUserNameReturns(currentUserName, nil) + fakeDisableSSHActor.GetCurrentUserReturns(configv3.User{Name: currentUserName}, nil) }) JustBeforeEach(func() { @@ -160,7 +161,6 @@ var _ = Describe("disable-ssh Command", func() { When("GetAppFeature action errors", func() { returnedErr := errors.New("some-error") BeforeEach(func() { - fakeDisableSSHActor.GetAppFeatureReturns( resources.ApplicationFeature{}, nil, diff --git a/command/v7/disallow_space_ssh_command.go b/command/v7/disallow_space_ssh_command.go index de22e9b586b..295d3d966de 100644 --- a/command/v7/disallow_space_ssh_command.go +++ b/command/v7/disallow_space_ssh_command.go @@ -14,13 +14,12 @@ type DisallowSpaceSSHCommand struct { } func (cmd *DisallowSpaceSSHCommand) Execute(args []string) error { - err := cmd.SharedActor.CheckTarget(true, false) if err != nil { return err } - currentUserName, err := cmd.Config.CurrentUserName() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } @@ -30,7 +29,7 @@ func (cmd *DisallowSpaceSSHCommand) Execute(args []string) error { cmd.UI.DisplayTextWithFlavor("Disabling ssh support for space {{.Space}} as {{.CurrentUserName}}...", map[string]interface{}{ "Space": inputSpace, - "CurrentUserName": currentUserName, + "CurrentUserName": currentUser.Name, }) warnings, err := cmd.Actor.UpdateSpaceFeature(inputSpace, targetedOrgGUID, false, "ssh") @@ -49,5 +48,4 @@ func (cmd *DisallowSpaceSSHCommand) Execute(args []string) error { cmd.UI.DisplayOK() return err - } diff --git a/command/v7/disallow_space_ssh_command_test.go b/command/v7/disallow_space_ssh_command_test.go index cbe6ca6bd39..d0dbe4bb951 100644 --- a/command/v7/disallow_space_ssh_command_test.go +++ b/command/v7/disallow_space_ssh_command_test.go @@ -8,6 +8,7 @@ import ( "code.cloudfoundry.org/cli/command/commandfakes" . "code.cloudfoundry.org/cli/command/v7" "code.cloudfoundry.org/cli/command/v7/v7fakes" + "code.cloudfoundry.org/cli/util/configv3" "code.cloudfoundry.org/cli/util/ui" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -47,7 +48,7 @@ var _ = Describe("disallow-space-ssh Command", func() { binaryName = "faceman" fakeConfig.BinaryNameReturns(binaryName) currentUserName = "some-user" - fakeConfig.CurrentUserNameReturns(currentUserName, nil) + disallowSpaceSSHActor.GetCurrentUserReturns(configv3.User{Name: currentUserName}, nil) }) JustBeforeEach(func() { @@ -71,7 +72,7 @@ var _ = Describe("disallow-space-ssh Command", func() { When("checking the current user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("", errors.New("uh oh")) + disallowSpaceSSHActor.GetCurrentUserReturns(configv3.User{}, errors.New("uh oh")) }) It("returns the error", func() { diff --git a/command/v7/domains_command.go b/command/v7/domains_command.go index 8a48279ecb1..09b59929f59 100644 --- a/command/v7/domains_command.go +++ b/command/v7/domains_command.go @@ -23,7 +23,7 @@ func (cmd DomainsCommand) Execute(args []string) error { return err } - currentUser, err := cmd.Config.CurrentUser() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/domains_command_test.go b/command/v7/domains_command_test.go index db853bd41e8..498e45370a2 100644 --- a/command/v7/domains_command_test.go +++ b/command/v7/domains_command_test.go @@ -89,7 +89,7 @@ var _ = Describe("domains Command", func() { Context("When the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) }) When("DomainsActor returns an error", func() { diff --git a/command/v7/download_droplet_command.go b/command/v7/download_droplet_command.go index 5c1b52609e9..0b4b55cb6a0 100644 --- a/command/v7/download_droplet_command.go +++ b/command/v7/download_droplet_command.go @@ -28,7 +28,7 @@ func (cmd DownloadDropletCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/download_droplet_command_test.go b/command/v7/download_droplet_command_test.go index 5f9d4b16a14..826ba8b12a6 100644 --- a/command/v7/download_droplet_command_test.go +++ b/command/v7/download_droplet_command_test.go @@ -58,7 +58,7 @@ var _ = Describe("download-droplet Command", func() { fakeConfig.TargetedSpaceReturns(configv3.Space{ GUID: "some-space-guid", Name: "some-space"}) - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) diff --git a/command/v7/droplets_command.go b/command/v7/droplets_command.go index a9b58e221ca..2e61020c71e 100644 --- a/command/v7/droplets_command.go +++ b/command/v7/droplets_command.go @@ -24,7 +24,7 @@ func (cmd DropletsCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/droplets_command_test.go b/command/v7/droplets_command_test.go index 554de013811..bd9ef93014c 100644 --- a/command/v7/droplets_command_test.go +++ b/command/v7/droplets_command_test.go @@ -60,7 +60,7 @@ var _ = Describe("droplets Command", func() { GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { @@ -87,7 +87,7 @@ var _ = Describe("droplets Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/enable_feature_flag_command.go b/command/v7/enable_feature_flag_command.go index 4ca569c9c85..f15945aa8e2 100644 --- a/command/v7/enable_feature_flag_command.go +++ b/command/v7/enable_feature_flag_command.go @@ -18,7 +18,7 @@ func (cmd EnableFeatureFlagCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/enable_feature_flag_command_test.go b/command/v7/enable_feature_flag_command_test.go index 5e0228ebd30..84717d362a4 100644 --- a/command/v7/enable_feature_flag_command_test.go +++ b/command/v7/enable_feature_flag_command_test.go @@ -70,7 +70,7 @@ var _ = Describe("Enable Feature Flag Command", func() { When("the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "apple"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "apple"}, nil) }) It("should print text indicating its running", func() { diff --git a/command/v7/enable_org_isolation_command.go b/command/v7/enable_org_isolation_command.go index 54bb5ad9a14..be089ce48c5 100644 --- a/command/v7/enable_org_isolation_command.go +++ b/command/v7/enable_org_isolation_command.go @@ -17,7 +17,7 @@ func (cmd EnableOrgIsolationCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/enable_org_isolation_command_test.go b/command/v7/enable_org_isolation_command_test.go index aa1b0579c29..ed6e1f29ad3 100644 --- a/command/v7/enable_org_isolation_command_test.go +++ b/command/v7/enable_org_isolation_command_test.go @@ -70,7 +70,7 @@ var _ = Describe("enable-org-isolation Command", func() { When("the user is logged in", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) cmd.RequiredArgs.OrganizationName = org cmd.RequiredArgs.IsolationSegmentName = isolationSegment diff --git a/command/v7/enable_service_access_command.go b/command/v7/enable_service_access_command.go index 82fbe5a485f..3246cf9a3e8 100644 --- a/command/v7/enable_service_access_command.go +++ b/command/v7/enable_service_access_command.go @@ -40,7 +40,7 @@ func (cmd EnableServiceAccessCommand) Execute(args []string) error { } func (cmd EnableServiceAccessCommand) displayMessage() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/enable_service_access_command_test.go b/command/v7/enable_service_access_command_test.go index b38d7b8a01d..b74631d2737 100644 --- a/command/v7/enable_service_access_command_test.go +++ b/command/v7/enable_service_access_command_test.go @@ -55,7 +55,7 @@ var _ = Describe("enable-service-access command", func() { DescribeTable( "message text", func(plan, org, broker, expected string) { - fakeConfig.CurrentUserReturns(configv3.User{Name: "fake-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "fake-user"}, nil) setPositionalFlags(&cmd, "fake-service") setFlag(&cmd, "-p", plan) diff --git a/command/v7/enable_ssh_command.go b/command/v7/enable_ssh_command.go index 7fadce6d718..836d2f9c487 100644 --- a/command/v7/enable_ssh_command.go +++ b/command/v7/enable_ssh_command.go @@ -18,14 +18,14 @@ func (cmd *EnableSSHCommand) Execute(args []string) error { return err } - username, err := cmd.Config.CurrentUserName() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } cmd.UI.DisplayTextWithFlavor("Enabling ssh support for app {{.AppName}} as {{.CurrentUserName}}...", map[string]interface{}{ "AppName": cmd.RequiredArgs.AppName, - "CurrentUserName": username, + "CurrentUserName": user.Name, }) app, getAppWarnings, err := cmd.Actor.GetApplicationByNameAndSpace(cmd.RequiredArgs.AppName, cmd.Config.TargetedSpace().GUID) diff --git a/command/v7/enable_ssh_command_test.go b/command/v7/enable_ssh_command_test.go index 8f6431e95be..6f10da55d7e 100644 --- a/command/v7/enable_ssh_command_test.go +++ b/command/v7/enable_ssh_command_test.go @@ -10,6 +10,7 @@ import ( . "code.cloudfoundry.org/cli/command/v7" "code.cloudfoundry.org/cli/command/v7/v7fakes" "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/configv3" "code.cloudfoundry.org/cli/util/ui" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -49,7 +50,7 @@ var _ = Describe("enable-ssh Command", func() { binaryName = "faceman" fakeConfig.BinaryNameReturns(binaryName) currentUserName = "some-user" - fakeConfig.CurrentUserNameReturns(currentUserName, nil) + fakeEnableSSHActor.GetCurrentUserReturns(configv3.User{Name: currentUserName}, nil) }) JustBeforeEach(func() { @@ -185,7 +186,6 @@ var _ = Describe("enable-ssh Command", func() { When("GetAppFeature action errors", func() { returnedErr := errors.New("some-error") BeforeEach(func() { - fakeEnableSSHActor.GetAppFeatureReturns( resources.ApplicationFeature{}, nil, diff --git a/command/v7/env_command.go b/command/v7/env_command.go index 84b05fdb8b8..a021cdfc02f 100644 --- a/command/v7/env_command.go +++ b/command/v7/env_command.go @@ -22,7 +22,7 @@ func (cmd EnvCommand) Execute(_ []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/env_command_test.go b/command/v7/env_command_test.go index f03a6d2dc6c..73ffa2d1baa 100644 --- a/command/v7/env_command_test.go +++ b/command/v7/env_command_test.go @@ -76,7 +76,7 @@ var _ = Describe("env Command", func() { When("getting the current user returns an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("some-error")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("some-error")) }) It("returns the error", func() { @@ -86,7 +86,7 @@ var _ = Describe("env Command", func() { When("getting the current user succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) }) When("getting the environment returns env vars for all groups", func() { diff --git a/command/v7/events_command.go b/command/v7/events_command.go index 566169ae6c7..bca46d76781 100644 --- a/command/v7/events_command.go +++ b/command/v7/events_command.go @@ -19,7 +19,7 @@ func (cmd EventsCommand) Execute(_ []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/events_command_test.go b/command/v7/events_command_test.go index 3873cba5b75..6f1e6faae61 100644 --- a/command/v7/events_command_test.go +++ b/command/v7/events_command_test.go @@ -60,7 +60,7 @@ var _ = Describe("events Command", func() { GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { @@ -87,7 +87,7 @@ var _ = Describe("events Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/feature_flag_command.go b/command/v7/feature_flag_command.go index 7d113030cd7..4a0db0e2aac 100644 --- a/command/v7/feature_flag_command.go +++ b/command/v7/feature_flag_command.go @@ -21,7 +21,7 @@ func (cmd FeatureFlagCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/feature_flag_command_test.go b/command/v7/feature_flag_command_test.go index c70a51e5f9c..8c6b191a134 100644 --- a/command/v7/feature_flag_command_test.go +++ b/command/v7/feature_flag_command_test.go @@ -50,7 +50,7 @@ var _ = Describe("Feature Flag Command", func() { fakeConfig.BinaryNameReturns(binaryName) cmd.RequiredArgs.Feature = featureFlagName - fakeConfig.CurrentUserReturns(configv3.User{Name: "apple"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "apple"}, nil) fakeActor.GetFeatureFlagByNameReturns(resources.FeatureFlag{ Name: "flag1", diff --git a/command/v7/feature_flags_command.go b/command/v7/feature_flags_command.go index 5d98ccd1147..64c6ce47d03 100644 --- a/command/v7/feature_flags_command.go +++ b/command/v7/feature_flags_command.go @@ -19,7 +19,7 @@ func (cmd FeatureFlagsCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/feature_flags_command_test.go b/command/v7/feature_flags_command_test.go index 9f86f63c819..c14ae693026 100644 --- a/command/v7/feature_flags_command_test.go +++ b/command/v7/feature_flags_command_test.go @@ -72,7 +72,7 @@ var _ = Describe("Feature Flags Command", func() { Context("When the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) }) When("FeatureFlagsActor returns an error", func() { diff --git a/command/v7/get_health_check_command.go b/command/v7/get_health_check_command.go index 1611d15f3d5..050f6a568de 100644 --- a/command/v7/get_health_check_command.go +++ b/command/v7/get_health_check_command.go @@ -21,7 +21,7 @@ func (cmd GetHealthCheckCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/get_health_check_command_test.go b/command/v7/get_health_check_command_test.go index 6e8a00ff003..de730ad5fcb 100644 --- a/command/v7/get_health_check_command_test.go +++ b/command/v7/get_health_check_command_test.go @@ -59,7 +59,7 @@ var _ = Describe("get-health-check Command", func() { GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { @@ -86,7 +86,7 @@ var _ = Describe("get-health-check Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/isolation_segments_command.go b/command/v7/isolation_segments_command.go index 4f77f3b305a..8eed00effa0 100644 --- a/command/v7/isolation_segments_command.go +++ b/command/v7/isolation_segments_command.go @@ -18,7 +18,7 @@ func (cmd IsolationSegmentsCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/isolation_segments_command_test.go b/command/v7/isolation_segments_command_test.go index bb6530e0359..88bd5ce1b42 100644 --- a/command/v7/isolation_segments_command_test.go +++ b/command/v7/isolation_segments_command_test.go @@ -66,7 +66,7 @@ var _ = Describe("isolation-segments Command", func() { When("checking target does not fail", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) }) When("an error is not encountered getting the isolation segment summaries", func() { diff --git a/command/v7/label_updater.go b/command/v7/label_updater.go index 948e58d9ef5..ce48fcd2854 100644 --- a/command/v7/label_updater.go +++ b/command/v7/label_updater.go @@ -9,11 +9,13 @@ import ( "code.cloudfoundry.org/cli/command" "code.cloudfoundry.org/cli/command/translatableerror" "code.cloudfoundry.org/cli/types" + "code.cloudfoundry.org/cli/util/configv3" ) //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . SetLabelActor type SetLabelActor interface { + GetCurrentUser() (configv3.User, error) UpdateApplicationLabelsByApplicationName(string, string, map[string]types.NullString) (v7action.Warnings, error) UpdateBuildpackLabelsByBuildpackNameAndStack(string, string, map[string]types.NullString) (v7action.Warnings, error) UpdateDomainLabelsByDomainName(string, map[string]types.NullString) (v7action.Warnings, error) @@ -60,12 +62,13 @@ func (cmd *LabelUpdater) Execute(targetResource TargetResource, labels map[strin cmd.labels = labels cmd.targetResource.ResourceType = strings.ToLower(cmd.targetResource.ResourceType) - var err error - cmd.Username, err = cmd.Config.CurrentUserName() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } + cmd.Username = user.Name + if err := cmd.validateFlags(); err != nil { return err } diff --git a/command/v7/label_updater_test.go b/command/v7/label_updater_test.go index 9e013384e9d..de8411f0aac 100644 --- a/command/v7/label_updater_test.go +++ b/command/v7/label_updater_test.go @@ -95,7 +95,7 @@ var _ = Describe("LabelUpdater", func() { ResourceType: "anything", ResourceName: resourceName, } - fakeConfig.CurrentUserNameReturns("some-user", errors.New("boom")) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, errors.New("boom")) }) It("returns an error", func() { @@ -238,11 +238,12 @@ var _ = Describe("LabelUpdater", func() { fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "fake-org"}) fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "fake-space", GUID: "some-space-guid"}) - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) expectedMap = map[string]types.NullString{ "some-label": types.NewNullString("some-value"), - "some-other-key": types.NewNullString()} + "some-other-key": types.NewNullString(), + } labels = expectedMap }) @@ -306,7 +307,7 @@ var _ = Describe("LabelUpdater", func() { When("Unsetting labels", func() { BeforeEach(func() { cmd.Action = Unset - //FIXME do we want to change the labels to all have nil values? + // FIXME do we want to change the labels to all have nil values? }) It("shows 'Removing' as action", func() { Expect(testUI.Out).To(Say(regexp.QuoteMeta(`Removing label(s) for app %s in org fake-org / space fake-space as some-user...`), appName)) @@ -316,7 +317,7 @@ var _ = Describe("LabelUpdater", func() { When("Setting labels", func() { BeforeEach(func() { cmd.Action = Set - //FIXME do we want to change the labels to all have not nil values? + // FIXME do we want to change the labels to all have not nil values? }) It("shows 'Setting' as action", func() { @@ -339,18 +340,18 @@ var _ = Describe("LabelUpdater", func() { } fakeSharedActor.CheckTargetReturns(nil) - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) expectedMap = map[string]types.NullString{ "some-label": types.NewNullString("some-value"), - "some-other-key": types.NewNullString()} + "some-other-key": types.NewNullString(), + } labels = expectedMap fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackReturns( v7action.Warnings([]string{"some-warning-1", "some-warning-2"}), nil, ) - }) JustBeforeEach(func() { @@ -404,7 +405,8 @@ var _ = Describe("LabelUpdater", func() { } expectedMap = map[string]types.NullString{ "some-label": types.NewNullString("some-value"), - "some-other-key": types.NewNullString()} + "some-other-key": types.NewNullString(), + } }) It("calls the right actor", func() { @@ -456,7 +458,7 @@ var _ = Describe("LabelUpdater", func() { When("Setting labels", func() { BeforeEach(func() { cmd.Action = Set - //FIXME do we want to change the labels to all have not nil values? + // FIXME do we want to change the labels to all have not nil values? }) When("stack is passed", func() { @@ -492,10 +494,11 @@ var _ = Describe("LabelUpdater", func() { } expectedMap = map[string]types.NullString{ "some-label": types.NewNullString("some-value"), - "some-other-key": types.NewNullString()} + "some-other-key": types.NewNullString(), + } labels = expectedMap - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeActor.UpdateDomainLabelsByDomainNameReturns( v7action.Warnings{"some-warning-1", "some-warning-2"}, nil, @@ -587,11 +590,12 @@ var _ = Describe("LabelUpdater", func() { ResourceName: orgName, } fakeSharedActor.CheckTargetReturns(nil) - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) expectedMap = map[string]types.NullString{ "some-label": types.NewNullString("some-value"), - "some-other-key": types.NewNullString()} + "some-other-key": types.NewNullString(), + } labels = expectedMap fakeActor.UpdateOrganizationLabelsByOrganizationNameReturns( @@ -687,10 +691,11 @@ var _ = Describe("LabelUpdater", func() { expectedMap = map[string]types.NullString{ "some-label": types.NewNullString("some-value"), - "some-other-key": types.NewNullString()} + "some-other-key": types.NewNullString(), + } labels = expectedMap - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "fake-org"}) fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "fake-space", GUID: "space-guid"}) fakeActor.UpdateRouteLabelsReturns(v7action.Warnings{"some-warning-1", "some-warning-2"}, @@ -782,7 +787,7 @@ var _ = Describe("LabelUpdater", func() { ResourceName: expectedServiceBrokerName, } - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) expectedMap = map[string]types.NullString{ "some-label": types.NewNullString("some-value"), "some-other-key": types.NewNullString(), @@ -887,11 +892,12 @@ var _ = Describe("LabelUpdater", func() { fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "fake-org"}) fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "fake-space", GUID: "some-space-guid"}) - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) expectedMap = map[string]types.NullString{ "some-label": types.NewNullString("some-value"), - "some-other-key": types.NewNullString()} + "some-other-key": types.NewNullString(), + } labels = expectedMap }) @@ -977,9 +983,7 @@ var _ = Describe("LabelUpdater", func() { }) When("updating labels on service-offering", func() { - var ( - executeErr error - ) + var executeErr error const serviceBrokerName = "brokerName" const serviceOfferingName = "serviceOfferingName" @@ -994,7 +998,7 @@ var _ = Describe("LabelUpdater", func() { "some-other-key": types.NewNullString(), } - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeActor.UpdateServiceOfferingLabelsReturns( v7action.Warnings{"some-warning-1", "some-warning-2"}, nil, @@ -1120,9 +1124,7 @@ var _ = Describe("LabelUpdater", func() { }) When("updating labels on service-plan", func() { - var ( - executeErr error - ) + var executeErr error const serviceBrokerName = "brokerName" const serviceOfferingName = "serviceOfferingName" @@ -1138,7 +1140,7 @@ var _ = Describe("LabelUpdater", func() { "some-other-key": types.NewNullString(), } - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeActor.UpdateServicePlanLabelsReturns( v7action.Warnings{"some-warning-1", "some-warning-2"}, nil, @@ -1330,7 +1332,6 @@ var _ = Describe("LabelUpdater", func() { }) }) }) - }) }) @@ -1349,10 +1350,11 @@ var _ = Describe("LabelUpdater", func() { } expectedMap = map[string]types.NullString{ "some-label": types.NewNullString("some-value"), - "some-other-key": types.NewNullString()} + "some-other-key": types.NewNullString(), + } labels = expectedMap - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeConfig.TargetedOrganizationReturns( configv3.Organization{Name: "fake-org", GUID: "some-org-guid"}) @@ -1450,7 +1452,7 @@ var _ = Describe("LabelUpdater", func() { ResourceType: "stack", ResourceName: stackName, } - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeSharedActor.CheckTargetReturns(nil) expectedMap = map[string]types.NullString{ "some-label": types.NewNullString("some-value"), @@ -1473,7 +1475,6 @@ var _ = Describe("LabelUpdater", func() { Expect(executeErr).ToNot(HaveOccurred()) Expect(testUI.Err).To(Say("some-warning-1")) Expect(testUI.Err).To(Say("some-warning-2")) - }) It("passes the correct parameters into the actor", func() { diff --git a/command/v7/labels_command.go b/command/v7/labels_command.go index f1bcf554ed4..4b371508558 100644 --- a/command/v7/labels_command.go +++ b/command/v7/labels_command.go @@ -47,11 +47,13 @@ func (cmd LabelsCommand) Execute(args []string) error { err error ) - cmd.username, err = cmd.Config.CurrentUserName() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } + cmd.username = user.Name + if err := cmd.validateFlags(); err != nil { return err } diff --git a/command/v7/labels_command_test.go b/command/v7/labels_command_test.go index 4c2ff51f567..200e4c78075 100644 --- a/command/v7/labels_command_test.go +++ b/command/v7/labels_command_test.go @@ -49,7 +49,7 @@ var _ = Describe("labels command", func() { Context("shared validations", func() { When("fetching the current user's name fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("some-user", errors.New("boom")) + fakeLabelsActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, errors.New("boom")) executeErr = cmd.Execute(nil) }) @@ -182,18 +182,16 @@ var _ = Describe("labels command", func() { } }) }) - }) Describe("listing labels", func() { - JustBeforeEach(func() { executeErr = cmd.Execute(nil) }) Describe("for apps", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeLabelsActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "fake-org"}) fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "fake-space", GUID: "some-space-guid"}) cmd.RequiredArgs = flag.LabelsArgs{ @@ -273,7 +271,7 @@ var _ = Describe("labels command", func() { Describe("for domains", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeLabelsActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) cmd.RequiredArgs = flag.LabelsArgs{ ResourceType: "domain", ResourceName: "example.com", @@ -346,12 +344,11 @@ var _ = Describe("labels command", func() { Expect(testUI.Out).ToNot(Say("OK")) }) }) - }) Describe("for orgs", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeLabelsActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) cmd.RequiredArgs = flag.LabelsArgs{ ResourceType: "org", ResourceName: "fake-org", @@ -422,12 +419,11 @@ var _ = Describe("labels command", func() { Expect(testUI.Out).ToNot(Say("OK")) }) }) - }) Describe("for routes", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeLabelsActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "fake-org"}) fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "fake-space", GUID: "some-space-guid"}) cmd.RequiredArgs = flag.LabelsArgs{ @@ -503,12 +499,11 @@ var _ = Describe("labels command", func() { Expect(testUI.Out).ToNot(Say("OK")) }) }) - }) Describe("for spaces", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeLabelsActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "fake-org", GUID: "some-org-guid"}) cmd.RequiredArgs = flag.LabelsArgs{ ResourceType: "space", @@ -580,12 +575,11 @@ var _ = Describe("labels command", func() { Expect(testUI.Out).ToNot(Say("OK")) }) }) - }) Describe("for stacks", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeLabelsActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) cmd.RequiredArgs = flag.LabelsArgs{ ResourceType: "stack", ResourceName: "fake-stack", @@ -656,12 +650,11 @@ var _ = Describe("labels command", func() { Expect(testUI.Out).ToNot(Say("OK")) }) }) - }) Describe("for buildpacks", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeLabelsActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) cmd.RequiredArgs = flag.LabelsArgs{ ResourceType: "buildpack", ResourceName: "my-buildpack", @@ -773,7 +766,7 @@ var _ = Describe("labels command", func() { Describe("for service-brokers", func() { When("There is an error fetching the labels", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeLabelsActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) cmd.RequiredArgs = flag.LabelsArgs{ ResourceType: "service-broker", @@ -804,7 +797,7 @@ var _ = Describe("labels command", func() { "some-label": types.NewNullString("some-value"), } - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeLabelsActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) cmd.RequiredArgs = flag.LabelsArgs{ ResourceType: "service-broker", @@ -831,14 +824,13 @@ var _ = Describe("labels command", func() { It("prints all the warnings", func() { Expect(testUI.Err).To(Say("some-warning-1")) Expect(testUI.Err).To(Say("some-warning-2")) - }) }) }) Describe("for service-instances", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeLabelsActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "fake-org"}) fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "fake-space", GUID: "some-space-guid"}) @@ -905,7 +897,7 @@ var _ = Describe("labels command", func() { Describe("for service-offerings", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeLabelsActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) cmd.RequiredArgs = flag.LabelsArgs{ ResourceType: "service-offering", @@ -990,7 +982,7 @@ var _ = Describe("labels command", func() { Describe("for service-plans", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeLabelsActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) cmd.RequiredArgs = flag.LabelsArgs{ ResourceType: "service-plan", diff --git a/command/v7/login_command.go b/command/v7/login_command.go index e1cb0ad80ca..a98aaf695ac 100644 --- a/command/v7/login_command.go +++ b/command/v7/login_command.go @@ -1,7 +1,6 @@ package v7 import ( - "errors" "fmt" "io" "net/url" @@ -16,6 +15,7 @@ import ( "code.cloudfoundry.org/cli/actor/v7action" "code.cloudfoundry.org/cli/api/uaa/constant" "code.cloudfoundry.org/cli/cf/configuration/coreconfig" + "code.cloudfoundry.org/cli/cf/errors" "code.cloudfoundry.org/cli/command" "code.cloudfoundry.org/cli/command/translatableerror" "code.cloudfoundry.org/cli/command/v7/shared" @@ -60,7 +60,7 @@ type LoginCommand struct { } func (cmd *LoginCommand) Setup(config command.Config, ui command.UI) error { - ccClient, _ := shared.NewWrappedCloudControllerClient(config, ui) + ccClient := shared.NewWrappedCloudControllerClient(config, ui) cmd.Actor = v7action.NewActor(ccClient, config, nil, nil, nil, clock.NewClock()) cmd.ActorReloader = ActualActorReloader{} @@ -98,6 +98,11 @@ func (cmd *LoginCommand) Execute(args []string) error { return err } + err = cmd.validateTargetSpecificFlags() + if err != nil { + return err + } + versionWarning, err := shared.CheckCCAPIVersion(cmd.Config.APIVersion()) if err != nil { cmd.UI.DisplayWarning("Warning: unable to determine whether targeted API's version meets minimum supported.") @@ -208,7 +213,7 @@ func (cmd *LoginCommand) determineAPIEndpoint() (v7action.TargetSettings, error) endpoint := cmd.APIEndpoint skipSSLValidation := cmd.SkipSSLValidation - var configTarget = cmd.Config.Target() + configTarget := cmd.Config.Target() if endpoint == "" && configTarget != "" { endpoint = configTarget @@ -255,7 +260,7 @@ func (cmd *LoginCommand) targetAPI(settings v7action.TargetSettings) error { func (cmd *LoginCommand) authenticate() error { var err error - var credentials = make(map[string]string) + credentials := make(map[string]string) prompts, err := cmd.Actor.GetLoginPrompts() if err != nil { @@ -272,7 +277,11 @@ func (cmd *LoginCommand) authenticate() error { } for key, prompt := range nonPasswordPrompts { - credentials[key], err = cmd.UI.DisplayTextPrompt(prompt.DisplayName) + if prompt.Type == coreconfig.AuthPromptTypeMenu { + credentials[key], err = cmd.UI.DisplayTextMenu(prompt.Entries, prompt.DisplayName) + } else { + credentials[key], err = cmd.UI.DisplayTextPrompt(prompt.DisplayName) + } if err != nil { return err } @@ -398,13 +407,13 @@ func (cmd *LoginCommand) showStatus() { }, } - user, err := cmd.Config.CurrentUserName() - if user == "" || err != nil { + user, err := cmd.Actor.GetCurrentUser() + if user.Name == "" || err != nil { cmd.UI.DisplayKeyValueTable("", tableContent, 3) command.DisplayNotLoggedInText(cmd.Config.BinaryName(), cmd.UI) return } - tableContent = append(tableContent, []string{cmd.UI.TranslateText("user:"), user}) + tableContent = append(tableContent, []string{cmd.UI.TranslateText("user:"), user.Name}) orgName := cmd.Config.TargetedOrganizationName() if orgName == "" { @@ -459,7 +468,6 @@ func (cmd *LoginCommand) promptChosenOrg(orgs []resources.Organization) (resourc } chosenOrgName, err := cmd.promptMenu(orgNames, "Select an org:", "Org") - if err != nil { if invalidChoice, ok := err.(ui.InvalidChoiceError); ok { if cmd.Space != "" { @@ -572,6 +580,29 @@ func (cmd *LoginCommand) validateFlags() error { return nil } +func (cmd *LoginCommand) validateTargetSpecificFlags() error { + if !cmd.Config.IsCFOnK8s() { + return nil + } + + if cmd.Password != "" { + return translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "-p"} + } + if cmd.SSO { + return translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "--sso"} + } + if cmd.SSOPasscode != "" { + return translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "--sso-passcode"} + } + if cmd.Username != "" { + return translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "-u"} + } + if cmd.Origin != "" { + return translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "--origin"} + } + return nil +} + func contains(s []string, v string) bool { for _, x := range s { if x == v { diff --git a/command/v7/login_command_test.go b/command/v7/login_command_test.go index 51b059834d5..b2bcb502230 100644 --- a/command/v7/login_command_test.go +++ b/command/v7/login_command_test.go @@ -123,6 +123,63 @@ var _ = Describe("login Command", func() { Expect(executeErr).To(MatchError(translatableerror.PasswordGrantTypeLogoutRequiredError{})) }) }) + + When("running against cf-on-k8s API", func() { + BeforeEach(func() { + fakeConfig.IsCFOnK8sReturns(true) + fakeConfig.TargetReturns("https://foo.bar") + }) + + When("password flag is provider", func() { + BeforeEach(func() { + cmd.Password = "pass" + }) + + It("returns unsupported flag error", func() { + Expect(executeErr).To(Equal(translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "-p"})) + }) + }) + + When("sso flag is provider", func() { + BeforeEach(func() { + cmd.SSO = true + }) + + It("returns unsupported flag error", func() { + Expect(executeErr).To(Equal(translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "--sso"})) + }) + }) + + When("sso passcode flag is provider", func() { + BeforeEach(func() { + cmd.SSOPasscode = "sso-pass" + }) + + It("returns unsupported flag error", func() { + Expect(executeErr).To(Equal(translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "--sso-passcode"})) + }) + }) + + When("username flag is provider", func() { + BeforeEach(func() { + cmd.Username = "my-user" + }) + + It("returns unsupported flag error", func() { + Expect(executeErr).To(Equal(translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "-u"})) + }) + }) + + When("origin flag is provider", func() { + BeforeEach(func() { + cmd.Origin = "my-origin" + }) + + It("returns unsupported flag error", func() { + Expect(executeErr).To(Equal(translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "--origin"})) + }) + }) + }) }) Describe("API Endpoint", func() { @@ -563,7 +620,7 @@ var _ = Describe("login Command", func() { When("authenticating succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("potatoface", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "potatoface"}, nil) _, err := input.Write([]byte("faker\nsomeaccount\nsomepassword\ngarbage\n")) Expect(err).ToNot(HaveOccurred()) }) @@ -643,7 +700,7 @@ var _ = Describe("login Command", func() { }, }, nil) - fakeConfig.CurrentUserNameReturns("potatoface", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "potatoface"}, nil) }) When("--sso flag is set", func() { @@ -723,7 +780,7 @@ var _ = Describe("login Command", func() { fakeActor.AuthenticateReturns(uaa.UnauthorizedError{ Message: "Bad credentials", }) - fakeConfig.CurrentUserNameReturns("", nil) + fakeActor.GetCurrentUserReturns(configv3.User{}, nil) _, err := input.Write([]byte("some-passcode\n")) Expect(err).ToNot(HaveOccurred()) }) @@ -768,7 +825,7 @@ var _ = Describe("login Command", func() { cmd.Username = "some-user" cmd.Password = "some-password" fakeConfig.APIVersionReturns("3.4.5") - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) }) It("writes to the config", func() { @@ -803,7 +860,7 @@ var _ = Describe("login Command", func() { cmd.Username = "some-user" cmd.Password = "some-password" fakeConfig.APIVersionReturns("3.4.5") - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) }) When("-o was passed", func() { @@ -873,7 +930,7 @@ var _ = Describe("login Command", func() { cmd.Username = "some-user" cmd.Password = "some-password" cmd.Space = "some-space" - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeConfig.TargetReturns("https://example.com") fakeActor.GetOrganizationsReturns( []resources.Organization{}, @@ -891,7 +948,7 @@ var _ = Describe("login Command", func() { When("no org valid org exists", func() { BeforeEach(func() { fakeActor.GetOrganizationsReturns( - []resources.Organization{resources.Organization{ + []resources.Organization{{ GUID: "some-org-guid", Name: "some-org-name", }}, @@ -919,10 +976,10 @@ var _ = Describe("login Command", func() { When("only one valid org exists", func() { BeforeEach(func() { fakeActor.GetOrganizationsReturns( - []resources.Organization{resources.Organization{ + []resources.Organization{{ GUID: "some-org-guid1", Name: "some-org-name1", - }, resources.Organization{ + }, { GUID: "some-org-guid2", Name: "some-org-name2", }}, @@ -944,15 +1001,15 @@ var _ = Describe("login Command", func() { BeforeEach(func() { fakeActor.GetOrganizationsReturns( []resources.Organization{ - resources.Organization{ + { GUID: "some-org-guid3", Name: "1234", }, - resources.Organization{ + { GUID: "some-org-guid1", Name: "some-org-name1", }, - resources.Organization{ + { GUID: "some-org-guid2", Name: "some-org-name2", }, @@ -975,7 +1032,7 @@ var _ = Describe("login Command", func() { When("filtering the orgs errors", func() { BeforeEach(func() { fakeActor.GetOrganizationsReturns( - []resources.Organization{resources.Organization{ + []resources.Organization{{ GUID: "some-org-guid", Name: "some-org-name", }}, @@ -1015,7 +1072,7 @@ var _ = Describe("login Command", func() { When("fetching the organizations succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeConfig.TargetReturns("https://example.com") }) @@ -1039,7 +1096,7 @@ var _ = Describe("login Command", func() { When("only one org exists", func() { BeforeEach(func() { fakeActor.GetOrganizationsReturns( - []resources.Organization{resources.Organization{ + []resources.Organization{{ GUID: "some-org-guid", Name: "some-org-name", }}, @@ -1061,15 +1118,15 @@ var _ = Describe("login Command", func() { BeforeEach(func() { fakeActor.GetOrganizationsReturns( []resources.Organization{ - resources.Organization{ + { GUID: "some-org-guid3", Name: "1234", }, - resources.Organization{ + { GUID: "some-org-guid1", Name: "some-org-name1", }, - resources.Organization{ + { GUID: "some-org-guid2", Name: "some-org-name2", }, @@ -1083,7 +1140,8 @@ var _ = Describe("login Command", func() { When("the position is valid", func() { BeforeEach(func() { fakeConfig.TargetedOrganizationReturns(configv3.Organization{ - GUID: "targeted-org-guid1"}) + GUID: "targeted-org-guid1", + }) fakeConfig.TargetedOrganizationNameReturns("targeted-org-name") _, err := input.Write([]byte("2\n")) Expect(err).ToNot(HaveOccurred()) @@ -1191,7 +1249,6 @@ var _ = Describe("login Command", func() { }) }) }) - }) When("more than 50 orgs exist", func() { @@ -1245,7 +1302,6 @@ var _ = Describe("login Command", func() { }) }) }) - }) }) @@ -1276,14 +1332,15 @@ var _ = Describe("login Command", func() { cmd.Username = "some-user" cmd.Password = "some-password" fakeConfig.APIVersionReturns("3.4.5") - fakeConfig.CurrentUserNameReturns("some-user", nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) }) When("an org has been successfully targeted", func() { BeforeEach(func() { fakeConfig.TargetedOrganizationReturns(configv3.Organization{ GUID: "targeted-org-guid", - Name: "targeted-org-name"}, + Name: "targeted-org-name", + }, ) fakeConfig.TargetedOrganizationNameReturns("targeted-org-name") }) @@ -1554,9 +1611,7 @@ var _ = Describe("login Command", func() { Expect(fakeConfig.SetSpaceInformationCallCount()).To(Equal(0)) }) }) - }) - }) When("the user enters text which is both a space name and a digit", func() { @@ -1653,7 +1708,6 @@ var _ = Describe("login Command", func() { It("does not target the space", func() { Expect(fakeConfig.SetSpaceInformationCallCount()).To(Equal(0)) }) - }) When("the space is not in the list", func() { @@ -1671,7 +1725,6 @@ var _ = Describe("login Command", func() { }) }) }) - }) }) diff --git a/command/v7/logout_command.go b/command/v7/logout_command.go index 1ac952e5c99..0e7850c977f 100644 --- a/command/v7/logout_command.go +++ b/command/v7/logout_command.go @@ -28,7 +28,7 @@ func (cmd *LogoutCommand) Setup(config command.Config, ui command.UI) error { } func (cmd LogoutCommand) Execute(args []string) error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/logout_command_test.go b/command/v7/logout_command_test.go index ba9561b1190..e0b09f5cb51 100644 --- a/command/v7/logout_command_test.go +++ b/command/v7/logout_command_test.go @@ -33,7 +33,7 @@ var _ = Describe("logout command", func() { }, } - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{ Name: "some-user", }, @@ -59,12 +59,12 @@ var _ = Describe("logout command", func() { When("unable to revoke token", func() { When("because the user is not logged in", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{}, nil) }) It("does not impact the logout", func() { Expect(executeErr).ToNot(HaveOccurred()) - Expect(fakeConfig.CurrentUserCallCount()).To(Equal(1)) + Expect(fakeActor.GetCurrentUserCallCount()).To(Equal(1)) Expect(fakeConfig.UnsetUserInformationCallCount()).To(Equal(1)) Expect(testUI.Out).To(Say("Logging out ...")) Expect(testUI.Out).To(Say("OK")) diff --git a/command/v7/logs_command.go b/command/v7/logs_command.go index 5093a143e24..e5232665010 100644 --- a/command/v7/logs_command.go +++ b/command/v7/logs_command.go @@ -38,7 +38,7 @@ func (cmd LogsCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/logs_command_test.go b/command/v7/logs_command_test.go index 530b7be0f6d..ea188379989 100644 --- a/command/v7/logs_command_test.go +++ b/command/v7/logs_command_test.go @@ -51,7 +51,7 @@ var _ = Describe("logs command", func() { binaryName = "faceman" fakeConfig.BinaryNameReturns(binaryName) cmd.RequiredArgs.AppName = "some-app" - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) }) JustBeforeEach(func() { diff --git a/command/v7/map_route_command.go b/command/v7/map_route_command.go index 4224b40741c..a9a4afe1bae 100644 --- a/command/v7/map_route_command.go +++ b/command/v7/map_route_command.go @@ -41,7 +41,7 @@ func (cmd MapRouteCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/map_route_command_test.go b/command/v7/map_route_command_test.go index 00e8154a7a8..a2be30ebd57 100644 --- a/command/v7/map_route_command_test.go +++ b/command/v7/map_route_command_test.go @@ -75,7 +75,7 @@ var _ = Describe("map-route Command", func() { GUID: spaceGUID, }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { @@ -102,7 +102,7 @@ var _ = Describe("map-route Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/marketplace_command.go b/command/v7/marketplace_command.go index 4b96f3a075a..47adc8eb88a 100644 --- a/command/v7/marketplace_command.go +++ b/command/v7/marketplace_command.go @@ -77,7 +77,7 @@ func (cmd MarketplaceCommand) processLoginContext() (string, error) { return "", err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return "", err } diff --git a/command/v7/marketplace_command_test.go b/command/v7/marketplace_command_test.go index 428797f573b..ca4410c572e 100644 --- a/command/v7/marketplace_command_test.go +++ b/command/v7/marketplace_command_test.go @@ -50,7 +50,7 @@ var _ = Describe("marketplace command", func() { Name: "fake-org-name", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "fake-username"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "fake-username"}, nil) }) Describe("pre-flight checks", func() { @@ -70,7 +70,7 @@ var _ = Describe("marketplace command", func() { }) It("gets the user", func() { - Expect(fakeConfig.CurrentUserCallCount()).To(Equal(1)) + Expect(fakeActor.GetCurrentUserCallCount()).To(Equal(1)) }) It("checks the target", func() { @@ -82,7 +82,7 @@ var _ = Describe("marketplace command", func() { When("getting the user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("fake get user error")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("fake get user error")) }) It("returns an error", func() { @@ -107,7 +107,7 @@ var _ = Describe("marketplace command", func() { }) It("does not try to get the username or check the target", func() { - Expect(fakeConfig.CurrentUserCallCount()).To(Equal(0)) + Expect(fakeActor.GetCurrentUserCallCount()).To(Equal(0)) Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(0)) }) }) diff --git a/command/v7/network_policies_command.go b/command/v7/network_policies_command.go index 5929ffab0ce..6a8a6e1f1d5 100644 --- a/command/v7/network_policies_command.go +++ b/command/v7/network_policies_command.go @@ -51,7 +51,7 @@ func (cmd NetworkPoliciesCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/network_policies_command_test.go b/command/v7/network_policies_command_test.go index 1b7886113b7..97b0fb57d0a 100644 --- a/command/v7/network_policies_command_test.go +++ b/command/v7/network_policies_command_test.go @@ -17,21 +17,23 @@ import ( var _ = Describe("network-policies Command", func() { var ( - cmd NetworkPoliciesCommand - testUI *ui.UI - fakeConfig *commandfakes.FakeConfig - fakeSharedActor *commandfakes.FakeSharedActor - fakeActor *v7fakes.FakeNetworkPoliciesActor - binaryName string - executeErr error - srcApp string + cmd NetworkPoliciesCommand + testUI *ui.UI + fakeConfig *commandfakes.FakeConfig + fakeSharedActor *commandfakes.FakeSharedActor + fakeActor *v7fakes.FakeActor + fakeNetworkPoliciesActor *v7fakes.FakeNetworkPoliciesActor + binaryName string + executeErr error + srcApp string ) BeforeEach(func() { testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) fakeConfig = new(commandfakes.FakeConfig) fakeSharedActor = new(commandfakes.FakeSharedActor) - fakeActor = new(v7fakes.FakeNetworkPoliciesActor) + fakeActor = new(v7fakes.FakeActor) + fakeNetworkPoliciesActor = new(v7fakes.FakeNetworkPoliciesActor) srcApp = "" @@ -40,8 +42,9 @@ var _ = Describe("network-policies Command", func() { Config: fakeConfig, SharedActor: fakeSharedActor, UI: testUI, + Actor: fakeActor, }, - NetworkingActor: fakeActor, + NetworkingActor: fakeNetworkPoliciesActor, SourceApp: srcApp, } @@ -70,7 +73,7 @@ var _ = Describe("network-policies Command", func() { When("the user is logged in", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "some-space", GUID: "some-space-guid"}) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org"}) }) @@ -81,7 +84,7 @@ var _ = Describe("network-policies Command", func() { When("fetching the user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("some-error")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("some-error")) }) It("returns an error", func() { @@ -91,7 +94,7 @@ var _ = Describe("network-policies Command", func() { When("listing policies is successful", func() { BeforeEach(func() { - fakeActor.NetworkPoliciesBySpaceReturns([]cfnetworkingaction.Policy{ + fakeNetworkPoliciesActor.NetworkPoliciesBySpaceReturns([]cfnetworkingaction.Policy{ { SourceName: "app1", DestinationName: "app2", @@ -114,8 +117,8 @@ var _ = Describe("network-policies Command", func() { It("lists the policies when no error occurs", func() { Expect(executeErr).ToNot(HaveOccurred()) - Expect(fakeActor.NetworkPoliciesBySpaceCallCount()).To(Equal(1)) - passedSpaceGuid := fakeActor.NetworkPoliciesBySpaceArgsForCall(0) + Expect(fakeNetworkPoliciesActor.NetworkPoliciesBySpaceCallCount()).To(Equal(1)) + passedSpaceGuid := fakeNetworkPoliciesActor.NetworkPoliciesBySpaceArgsForCall(0) Expect(passedSpaceGuid).To(Equal("some-space-guid")) Expect(testUI.Out).To(Say(`Listing network policies in org some-org / space some-space as some-user\.\.\.`)) @@ -131,7 +134,7 @@ var _ = Describe("network-policies Command", func() { When("a source app name is passed", func() { BeforeEach(func() { cmd.SourceApp = "some-app" - fakeActor.NetworkPoliciesBySpaceAndAppNameReturns([]cfnetworkingaction.Policy{ + fakeNetworkPoliciesActor.NetworkPoliciesBySpaceAndAppNameReturns([]cfnetworkingaction.Policy{ { SourceName: "app1", DestinationName: "app2", @@ -154,8 +157,8 @@ var _ = Describe("network-policies Command", func() { It("lists the policies when no error occurs", func() { Expect(executeErr).ToNot(HaveOccurred()) - Expect(fakeActor.NetworkPoliciesBySpaceAndAppNameCallCount()).To(Equal(1)) - passedSpaceGuid, passedSrcAppName := fakeActor.NetworkPoliciesBySpaceAndAppNameArgsForCall(0) + Expect(fakeNetworkPoliciesActor.NetworkPoliciesBySpaceAndAppNameCallCount()).To(Equal(1)) + passedSpaceGuid, passedSrcAppName := fakeNetworkPoliciesActor.NetworkPoliciesBySpaceAndAppNameArgsForCall(0) Expect(passedSpaceGuid).To(Equal("some-space-guid")) Expect(passedSrcAppName).To(Equal("some-app")) @@ -173,7 +176,7 @@ var _ = Describe("network-policies Command", func() { When("listing the policies is not successful", func() { BeforeEach(func() { - fakeActor.NetworkPoliciesBySpaceReturns([]cfnetworkingaction.Policy{}, cfnetworkingaction.Warnings{"some-warning-1", "some-warning-2"}, actionerror.ApplicationNotFoundError{Name: srcApp}) + fakeNetworkPoliciesActor.NetworkPoliciesBySpaceReturns([]cfnetworkingaction.Policy{}, cfnetworkingaction.Warnings{"some-warning-1", "some-warning-2"}, actionerror.ApplicationNotFoundError{Name: srcApp}) }) It("displays warnings and returns the error", func() { diff --git a/command/v7/org_command.go b/command/v7/org_command.go index 972cd68bfe0..0f2a238713c 100644 --- a/command/v7/org_command.go +++ b/command/v7/org_command.go @@ -43,7 +43,7 @@ func (cmd OrgCommand) displayOrgGUID() error { } func (cmd OrgCommand) displayOrgSummary() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/org_command_test.go b/command/v7/org_command_test.go index a66260b5ca2..2dccc3a8c49 100644 --- a/command/v7/org_command_test.go +++ b/command/v7/org_command_test.go @@ -134,7 +134,7 @@ var _ = Describe("org Command", func() { When("the --guid flag is not provided", func() { When("no errors occur", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{ Name: "some-user", }, @@ -195,7 +195,7 @@ var _ = Describe("org Command", func() { Expect(testUI.Out).To(Say(`spaces:\s+space1, space2`)) Expect(testUI.Out).To(Say(`isolation segments:\s+isolation-segment-1 \(default\), isolation-segment-2`)) - Expect(fakeConfig.CurrentUserCallCount()).To(Equal(1)) + Expect(fakeActor.GetCurrentUserCallCount()).To(Equal(1)) Expect(fakeActor.GetOrganizationSummaryByNameCallCount()).To(Equal(1)) orgName := fakeActor.GetOrganizationSummaryByNameArgsForCall(0) @@ -231,7 +231,7 @@ var _ = Describe("org Command", func() { BeforeEach(func() { expectedErr = errors.New("getting current user error") - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{}, expectedErr) }) diff --git a/command/v7/org_quota_command.go b/command/v7/org_quota_command.go index 9f55424a7b6..5458bb24fb7 100644 --- a/command/v7/org_quota_command.go +++ b/command/v7/org_quota_command.go @@ -20,7 +20,7 @@ func (cmd OrgQuotaCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/org_quota_command_test.go b/command/v7/org_quota_command_test.go index dcff1b5813c..187fcda8d56 100644 --- a/command/v7/org_quota_command_test.go +++ b/command/v7/org_quota_command_test.go @@ -65,7 +65,7 @@ var _ = Describe("Org Quota Command", func() { When("getting the org quota fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{ Name: "some-user", }, @@ -90,7 +90,7 @@ var _ = Describe("Org Quota Command", func() { When("getting the org quota succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{ Name: "some-user", }, diff --git a/command/v7/org_quotas_command.go b/command/v7/org_quotas_command.go index d774c48a236..2fb561d07f0 100644 --- a/command/v7/org_quotas_command.go +++ b/command/v7/org_quotas_command.go @@ -18,7 +18,7 @@ func (cmd OrgQuotasCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/org_quotas_command_test.go b/command/v7/org_quotas_command_test.go index 0096fe1927c..d69e632c6f0 100644 --- a/command/v7/org_quotas_command_test.go +++ b/command/v7/org_quotas_command_test.go @@ -57,7 +57,7 @@ var _ = Describe("org-quotas command", func() { When("running the command successfully", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "apple"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "apple"}, nil) orgQuotas := []resources.OrganizationQuota{ { Quota: resources.Quota{ @@ -160,7 +160,7 @@ var _ = Describe("org-quotas command", func() { When("the quota list is empty", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "apple"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "apple"}, nil) fakeActor.GetOrganizationQuotasReturns([]resources.OrganizationQuota{}, v7action.Warnings{"some-warning-1", "some-warning-2"}, nil) }) diff --git a/command/v7/org_users_command.go b/command/v7/org_users_command.go index 16434e85611..f7af79783b4 100644 --- a/command/v7/org_users_command.go +++ b/command/v7/org_users_command.go @@ -22,7 +22,7 @@ func (cmd *OrgUsersCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/org_users_command_test.go b/command/v7/org_users_command_test.go index 848529da91b..cdba41439e2 100644 --- a/command/v7/org_users_command_test.go +++ b/command/v7/org_users_command_test.go @@ -75,7 +75,7 @@ var _ = Describe("org-users Command", func() { When("getting the current user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("get-current-user-error")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("get-current-user-error")) }) It("returns the error", func() { @@ -85,7 +85,7 @@ var _ = Describe("org-users Command", func() { When("getting the current user succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) diff --git a/command/v7/orgs_command.go b/command/v7/orgs_command.go index 5a5ed52fc97..92c2cd179b4 100644 --- a/command/v7/orgs_command.go +++ b/command/v7/orgs_command.go @@ -19,7 +19,7 @@ func (cmd OrgsCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/orgs_command_test.go b/command/v7/orgs_command_test.go index c2da3108c85..161ee27f9c7 100644 --- a/command/v7/orgs_command_test.go +++ b/command/v7/orgs_command_test.go @@ -68,7 +68,7 @@ var _ = Describe("orgs Command", func() { When("the user is logged in and an org is targeted", func() { When("getting the current user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("get-user-error")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("get-user-error")) }) It("returns the error", func() { @@ -78,7 +78,7 @@ var _ = Describe("orgs Command", func() { When("getting the current user succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) diff --git a/command/v7/packages_command.go b/command/v7/packages_command.go index 0d35de66dbf..2aa01385d7f 100644 --- a/command/v7/packages_command.go +++ b/command/v7/packages_command.go @@ -22,7 +22,7 @@ func (cmd PackagesCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/packages_command_test.go b/command/v7/packages_command_test.go index f1d77c97147..87ae1f29039 100644 --- a/command/v7/packages_command_test.go +++ b/command/v7/packages_command_test.go @@ -59,7 +59,7 @@ var _ = Describe("packages Command", func() { GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { @@ -86,7 +86,7 @@ var _ = Describe("packages Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/passwd_command.go b/command/v7/passwd_command.go index fcdf18d79e2..f68baa1cb12 100644 --- a/command/v7/passwd_command.go +++ b/command/v7/passwd_command.go @@ -16,7 +16,7 @@ func (cmd PasswdCommand) Execute(args []string) error { return err } - currentUser, err := cmd.Config.CurrentUser() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/passwd_command_test.go b/command/v7/passwd_command_test.go index 64066a02f28..8a3bf5d3972 100644 --- a/command/v7/passwd_command_test.go +++ b/command/v7/passwd_command_test.go @@ -42,7 +42,7 @@ var _ = Describe("passwd Command", func() { }, } - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve", GUID: "steve-guid"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve", GUID: "steve-guid"}, nil) fakeUI.DisplayPasswordPromptReturnsOnCall(0, "old1", nil) fakeUI.DisplayPasswordPromptReturnsOnCall(1, "new1", nil) @@ -98,7 +98,7 @@ var _ = Describe("passwd Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/purge_service_instance_command.go b/command/v7/purge_service_instance_command.go index 653b39d01fc..fc646e47cf8 100644 --- a/command/v7/purge_service_instance_command.go +++ b/command/v7/purge_service_instance_command.go @@ -67,7 +67,7 @@ func (cmd PurgeServiceInstanceCommand) Usage() string { } func (cmd PurgeServiceInstanceCommand) displayEvent() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/purge_service_instance_command_test.go b/command/v7/purge_service_instance_command_test.go index f93aea04e88..d5f3e7e32f3 100644 --- a/command/v7/purge_service_instance_command_test.go +++ b/command/v7/purge_service_instance_command_test.go @@ -110,7 +110,7 @@ var _ = Describe("purge-service-instance command", func() { fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: orgName}) fakeConfig.TargetedSpaceReturns(configv3.Space{Name: spaceName, GUID: spaceGUID}) - fakeConfig.CurrentUserReturns(configv3.User{Name: username}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: username}, nil) cmd = PurgeServiceInstanceCommand{ BaseCommand: BaseCommand{ @@ -201,7 +201,7 @@ var _ = Describe("purge-service-instance command", func() { When("getting the username fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("boom")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("boom")) confirmYes() }) diff --git a/command/v7/push_command.go b/command/v7/push_command.go index 4d6b48019e6..c7becf02fef 100644 --- a/command/v7/push_command.go +++ b/command/v7/push_command.go @@ -146,7 +146,7 @@ func (cmd PushCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/push_command_test.go b/command/v7/push_command_test.go index eba133c0599..6d5d77fdcef 100644 --- a/command/v7/push_command_test.go +++ b/command/v7/push_command_test.go @@ -188,7 +188,7 @@ var _ = Describe("push Command", func() { When("the user is logged in, and org and space are targeted", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: userName}, nil) + fakeDiffActor.GetCurrentUserReturns(configv3.User{Name: userName}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{ Name: orgName, @@ -415,7 +415,6 @@ var _ = Describe("push Command", func() { Expect(executeErr).To(MatchError("apply-manifest-error")) Expect(testUI.Err).To(Say("apply-manifest-warnings")) }) - }) When("applying the manifest succeeds", func() { @@ -451,15 +450,14 @@ var _ = Describe("push Command", func() { Expect(executeErr).To(MatchError("create-push-plans-error")) Expect(testUI.Err).To(Say("create-push-plans-warnings")) }) - }) When("creating the push plans succeeds", func() { BeforeEach(func() { fakeActor.CreatePushPlansReturns( []v7pushaction.PushPlan{ - v7pushaction.PushPlan{Application: resources.Application{Name: "first-app", GUID: "potato"}}, - v7pushaction.PushPlan{Application: resources.Application{Name: "second-app", GUID: "potato"}}, + {Application: resources.Application{Name: "first-app", GUID: "potato"}}, + {Application: resources.Application{Name: "second-app", GUID: "potato"}}, }, v7action.Warnings{"create-push-plans-warnings"}, nil, @@ -593,7 +591,6 @@ var _ = Describe("push Command", func() { passedAppName, spaceGUID, _ = fakeVersionActor.GetStreamingLogsForApplicationByNameAndSpaceArgsForCall(1) Expect(passedAppName).To(Equal(appName2)) Expect(spaceGUID).To(Equal("some-space-guid")) - }) }) @@ -665,7 +662,6 @@ var _ = Describe("push Command", func() { Expect(testUI.Err).To(Say("get-application-summary-warnings")) }) }) - }) When("actualize returns an error", func() { diff --git a/command/v7/remove_network_policy_command.go b/command/v7/remove_network_policy_command.go index b7d2dee1ea6..c959bd40678 100644 --- a/command/v7/remove_network_policy_command.go +++ b/command/v7/remove_network_policy_command.go @@ -81,7 +81,7 @@ func (cmd RemoveNetworkPolicyCommand) Execute(args []string) error { destSpaceGUID = destSpace.GUID } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/remove_network_policy_command_test.go b/command/v7/remove_network_policy_command_test.go index 796a00fdff9..66247bc31ff 100644 --- a/command/v7/remove_network_policy_command_test.go +++ b/command/v7/remove_network_policy_command_test.go @@ -84,7 +84,7 @@ var _ = Describe("remove-network-policy Command", func() { When("the user is logged in", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "some-space", GUID: "some-space-guid"}) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org"}) }) diff --git a/command/v7/rename_command.go b/command/v7/rename_command.go index 2680ca77283..a2bb0b6efe0 100644 --- a/command/v7/rename_command.go +++ b/command/v7/rename_command.go @@ -17,7 +17,7 @@ func (cmd RenameCommand) Execute(args []string) error { if err != nil { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/rename_command_test.go b/command/v7/rename_command_test.go index c5af690ee88..4700666540b 100644 --- a/command/v7/rename_command_test.go +++ b/command/v7/rename_command_test.go @@ -45,7 +45,7 @@ var _ = Describe("rename Command", func() { cmd.RequiredArgs.OldAppName = "old-app-name" cmd.RequiredArgs.NewAppName = "new-app-name" - fakeConfig.CurrentUserReturns(configv3.User{Name: "username"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "username"}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "targeted-org"}) fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "targeted-space"}) fakeActor.RenameApplicationByNameAndSpaceGUIDReturns(resources.Application{Name: "new-app-name"}, v7action.Warnings{"rename-app-warning"}, nil) @@ -86,7 +86,7 @@ var _ = Describe("rename Command", func() { ) BeforeEach(func() { returnedError = errors.New("current user not found") - fakeConfig.CurrentUserReturns(configv3.User{}, returnedError) + fakeActor.GetCurrentUserReturns(configv3.User{}, returnedError) }) It("returns the CurrentUser error", func() { Expect(executeErr).To(MatchError(returnedError)) diff --git a/command/v7/rename_org_command.go b/command/v7/rename_org_command.go index 94f18aec7fa..628095f80d5 100644 --- a/command/v7/rename_org_command.go +++ b/command/v7/rename_org_command.go @@ -18,7 +18,7 @@ func (cmd RenameOrgCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/rename_org_command_test.go b/command/v7/rename_org_command_test.go index 45ad25e0cc8..5a61f65bb23 100644 --- a/command/v7/rename_org_command_test.go +++ b/command/v7/rename_org_command_test.go @@ -48,7 +48,7 @@ var _ = Describe("rename-org Command", func() { binaryName = "faceman" fakeConfig.BinaryNameReturns(binaryName) - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) }) JustBeforeEach(func() { @@ -61,7 +61,7 @@ var _ = Describe("rename-org Command", func() { BeforeEach(func() { returnedErr = errors.New("some error") - fakeConfig.CurrentUserReturns(configv3.User{}, returnedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, returnedErr) }) It("returns the error", func() { @@ -70,7 +70,7 @@ var _ = Describe("rename-org Command", func() { }) When("when the command succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "username"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "username"}, nil) fakeActor.RenameOrganizationReturns( resources.Organization{GUID: "old-org-guid", Name: "new-org-name"}, v7action.Warnings{"warning-1", "warning-2"}, diff --git a/command/v7/rename_service_broker_command.go b/command/v7/rename_service_broker_command.go index aa586cef1c7..4cd5ad001a8 100644 --- a/command/v7/rename_service_broker_command.go +++ b/command/v7/rename_service_broker_command.go @@ -24,7 +24,7 @@ func (cmd *RenameServiceBrokerCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/rename_service_broker_command_test.go b/command/v7/rename_service_broker_command_test.go index 3eb552a8ff9..c5cc9947952 100644 --- a/command/v7/rename_service_broker_command_test.go +++ b/command/v7/rename_service_broker_command_test.go @@ -59,7 +59,7 @@ var _ = Describe("rename-service-broker command", func() { nil, ) - fakeConfig.CurrentUserReturns(configv3.User{Name: "user"}, nil) + fakeUpdateServiceBrokerActor.GetCurrentUserReturns(configv3.User{Name: "user"}, nil) }) When("rename succeeds", func() { @@ -126,7 +126,7 @@ var _ = Describe("rename-service-broker command", func() { When("it fails to get the current user", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("no user found")) + fakeUpdateServiceBrokerActor.GetCurrentUserReturns(configv3.User{}, errors.New("no user found")) }) It("returns the error and displays all warnings", func() { diff --git a/command/v7/rename_service_command.go b/command/v7/rename_service_command.go index d69e6d331c5..f298e75c307 100644 --- a/command/v7/rename_service_command.go +++ b/command/v7/rename_service_command.go @@ -49,7 +49,7 @@ func (cmd RenameServiceCommand) Usage() string { } func (cmd RenameServiceCommand) displayMessage() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/rename_service_command_test.go b/command/v7/rename_service_command_test.go index 0bd659484c0..1a7aeeca305 100644 --- a/command/v7/rename_service_command_test.go +++ b/command/v7/rename_service_command_test.go @@ -60,7 +60,7 @@ var _ = Describe("rename-service command test", func() { fakeConfig.TargetedSpaceReturns(configv3.Space{GUID: spaceGUID, Name: spaceName}) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: orgName}) - fakeConfig.CurrentUserReturns(configv3.User{Name: username}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: username}, nil) fakeActor.RenameServiceInstanceReturns(v7action.Warnings{"rename instance warning"}, nil) }) @@ -107,7 +107,7 @@ var _ = Describe("rename-service command test", func() { When("getting the user returns an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("bang")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("bang")) }) It("returns the error", func() { diff --git a/command/v7/rename_space_command.go b/command/v7/rename_space_command.go index af1e0ee28db..cf63ebf7d14 100644 --- a/command/v7/rename_space_command.go +++ b/command/v7/rename_space_command.go @@ -18,7 +18,7 @@ func (cmd RenameSpaceCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/rename_space_command_test.go b/command/v7/rename_space_command_test.go index d425f0146d1..fbb020fdb8e 100644 --- a/command/v7/rename_space_command_test.go +++ b/command/v7/rename_space_command_test.go @@ -49,7 +49,7 @@ var _ = Describe("rename-space Command", func() { binaryName = "faceman" fakeConfig.BinaryNameReturns(binaryName) - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) }) JustBeforeEach(func() { @@ -78,7 +78,7 @@ var _ = Describe("rename-space Command", func() { BeforeEach(func() { returnedErr = errors.New("some error") - fakeConfig.CurrentUserReturns(configv3.User{}, returnedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, returnedErr) }) It("returns the error", func() { @@ -88,7 +88,7 @@ var _ = Describe("rename-space Command", func() { When("when the command succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "username"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "username"}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-targeted-org", GUID: "org-guid"}) fakeActor.RenameSpaceByNameAndOrganizationGUIDReturns( resources.Space{GUID: "old-space-guid", Name: "new-space-name"}, diff --git a/command/v7/reset_org_default_isolation_segment_command.go b/command/v7/reset_org_default_isolation_segment_command.go index bd10206ddf8..26763b4ff45 100644 --- a/command/v7/reset_org_default_isolation_segment_command.go +++ b/command/v7/reset_org_default_isolation_segment_command.go @@ -18,7 +18,7 @@ func (cmd ResetOrgDefaultIsolationSegmentCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/reset_org_default_isolation_segment_command_test.go b/command/v7/reset_org_default_isolation_segment_command_test.go index 96b11c9c7e0..aa76bf487f8 100644 --- a/command/v7/reset_org_default_isolation_segment_command_test.go +++ b/command/v7/reset_org_default_isolation_segment_command_test.go @@ -82,19 +82,19 @@ var _ = Describe("reset-org-default-isolation-segment Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { Expect(executeErr).To(Equal(expectedErr)) - Expect(fakeConfig.CurrentUserCallCount()).To(Equal(1)) + Expect(fakeActor.GetCurrentUserCallCount()).To(Equal(1)) }) }) When("the user is logged in", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) }) When("the org lookup is unsuccessful", func() { diff --git a/command/v7/reset_space_isolation_segment_command.go b/command/v7/reset_space_isolation_segment_command.go index 7ad5c4dd8a8..4d878135064 100644 --- a/command/v7/reset_space_isolation_segment_command.go +++ b/command/v7/reset_space_isolation_segment_command.go @@ -18,7 +18,7 @@ func (cmd ResetSpaceIsolationSegmentCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/reset_space_isolation_segment_command_test.go b/command/v7/reset_space_isolation_segment_command_test.go index 732863260ba..0a8638d2422 100644 --- a/command/v7/reset_space_isolation_segment_command_test.go +++ b/command/v7/reset_space_isolation_segment_command_test.go @@ -71,7 +71,7 @@ var _ = Describe("reset-space-isolation-segment Command", func() { When("the user is logged in", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{ Name: org, GUID: "some-org-guid", diff --git a/command/v7/restage_command.go b/command/v7/restage_command.go index 1b43bafd3e3..628bd852130 100644 --- a/command/v7/restage_command.go +++ b/command/v7/restage_command.go @@ -41,7 +41,7 @@ func (cmd RestageCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/restage_command_test.go b/command/v7/restage_command_test.go index 714dc4be175..7de6e0488b1 100644 --- a/command/v7/restage_command_test.go +++ b/command/v7/restage_command_test.go @@ -61,7 +61,7 @@ var _ = Describe("restage Command", func() { Name: "some-space", GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) fakeSharedActor.CheckTargetReturns(nil) fakeActor.GetApplicationByNameAndSpaceReturns( app, @@ -97,7 +97,7 @@ var _ = Describe("restage Command", func() { When("the user is not logged in", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/restart_app_instance_command.go b/command/v7/restart_app_instance_command.go index d2598da20b1..756f3941022 100644 --- a/command/v7/restart_app_instance_command.go +++ b/command/v7/restart_app_instance_command.go @@ -19,7 +19,7 @@ func (cmd RestartAppInstanceCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/restart_app_instance_command_test.go b/command/v7/restart_app_instance_command_test.go index feb88a99787..4108024c61a 100644 --- a/command/v7/restart_app_instance_command_test.go +++ b/command/v7/restart_app_instance_command_test.go @@ -81,7 +81,7 @@ var _ = Describe("restart-app-instance Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { @@ -98,7 +98,7 @@ var _ = Describe("restart-app-instance Command", func() { Name: "some-space", GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) When("restarting the specified instance returns an error", func() { diff --git a/command/v7/restart_command.go b/command/v7/restart_command.go index 4e4b6e5e216..66652cc0cf8 100644 --- a/command/v7/restart_command.go +++ b/command/v7/restart_command.go @@ -38,7 +38,7 @@ func (cmd RestartCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/restart_command_test.go b/command/v7/restart_command_test.go index 41eb6d74dcf..fbe3f8b6d5c 100644 --- a/command/v7/restart_command_test.go +++ b/command/v7/restart_command_test.go @@ -55,7 +55,7 @@ var _ = Describe("restart Command", func() { Name: "some-space", GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) fakeActor.GetApplicationByNameAndSpaceReturns(app, v7action.Warnings{"get-app-warning"}, nil) cmd = v7.RestartCommand{ @@ -97,7 +97,7 @@ var _ = Describe("restart Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/revisions_command.go b/command/v7/revisions_command.go index c20d4b72f23..c6c484fff5b 100644 --- a/command/v7/revisions_command.go +++ b/command/v7/revisions_command.go @@ -34,7 +34,7 @@ func (cmd RevisionsCommand) Execute(_ []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/revisions_command_test.go b/command/v7/revisions_command_test.go index 63c07c0cd07..8323069fa27 100644 --- a/command/v7/revisions_command_test.go +++ b/command/v7/revisions_command_test.go @@ -86,7 +86,7 @@ var _ = Describe("revisions Command", func() { When("getting the current user returns an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("some-error")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("some-error")) }) It("returns the error", func() { @@ -96,7 +96,7 @@ var _ = Describe("revisions Command", func() { When("getting the current user succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) }) When("when revisions are available", func() { diff --git a/command/v7/rollback_command.go b/command/v7/rollback_command.go index ea832ce8216..8c3e0f005ca 100644 --- a/command/v7/rollback_command.go +++ b/command/v7/rollback_command.go @@ -44,7 +44,7 @@ func (cmd RollbackCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/rollback_command_test.go b/command/v7/rollback_command_test.go index 70255407600..ac2a0aa7ce5 100644 --- a/command/v7/rollback_command_test.go +++ b/command/v7/rollback_command_test.go @@ -55,7 +55,7 @@ var _ = Describe("rollback Command", func() { ) fakeConfig.BinaryNameReturns(binaryName) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{ Name: "some-org", GUID: "some-org-guid", @@ -107,7 +107,7 @@ var _ = Describe("rollback Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("returns an error", func() { diff --git a/command/v7/route_command.go b/command/v7/route_command.go index 5c89398e8ff..9e4aa0ba1a3 100644 --- a/command/v7/route_command.go +++ b/command/v7/route_command.go @@ -40,7 +40,7 @@ func (cmd RouteCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/route_command_test.go b/command/v7/route_command_test.go index 2d616beafb4..331ed929805 100644 --- a/command/v7/route_command_test.go +++ b/command/v7/route_command_test.go @@ -51,7 +51,7 @@ var _ = Describe("route Command", func() { fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "some-space", GUID: "some-space-guid"}) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org"}) - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeActor.GetDomainByNameReturns( resources.Domain{Name: domainName, GUID: "domain-guid"}, @@ -94,12 +94,12 @@ var _ = Describe("route Command", func() { }) It("checks if the user is logged in", func() { - Expect(fakeConfig.CurrentUserCallCount()).To(Equal(1)) + Expect(fakeActor.GetCurrentUserCallCount()).To(Equal(1)) }) When("the user is not logged in", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("no current user")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("no current user")) }) It("returns an error", func() { diff --git a/command/v7/router_groups_command.go b/command/v7/router_groups_command.go index dabc5413dc4..924d8b44e08 100644 --- a/command/v7/router_groups_command.go +++ b/command/v7/router_groups_command.go @@ -18,7 +18,7 @@ func (cmd RouterGroupsCommand) Execute(args []string) error { return err } - currentUser, err := cmd.Config.CurrentUser() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/router_groups_command_test.go b/command/v7/router_groups_command_test.go index 78ce446f71c..32c64b543b2 100644 --- a/command/v7/router_groups_command_test.go +++ b/command/v7/router_groups_command_test.go @@ -71,7 +71,7 @@ var _ = Describe("router-groups Command", func() { Context("when the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) }) When("getting router groups succeeds", func() { diff --git a/command/v7/routes_command.go b/command/v7/routes_command.go index e0c2fd8a0f4..4edbd263f12 100644 --- a/command/v7/routes_command.go +++ b/command/v7/routes_command.go @@ -30,7 +30,7 @@ func (cmd RoutesCommand) Execute(args []string) error { return err } - currentUser, err := cmd.Config.CurrentUser() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/routes_command_test.go b/command/v7/routes_command_test.go index 9b7699124f1..e1bcceacfe8 100644 --- a/command/v7/routes_command_test.go +++ b/command/v7/routes_command_test.go @@ -88,7 +88,7 @@ var _ = Describe("routes Command", func() { When("the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{ GUID: "some-org-guid", Name: "some-org", diff --git a/command/v7/run_task_command.go b/command/v7/run_task_command.go index 47719b0d31b..c01bbe2e243 100644 --- a/command/v7/run_task_command.go +++ b/command/v7/run_task_command.go @@ -28,7 +28,7 @@ func (cmd RunTaskCommand) Execute(args []string) error { space := cmd.Config.TargetedSpace() - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/run_task_command_test.go b/command/v7/run_task_command_test.go index 90b8c0caed5..34233afe90b 100644 --- a/command/v7/run_task_command_test.go +++ b/command/v7/run_task_command_test.go @@ -90,7 +90,7 @@ var _ = Describe("run-task Command", func() { BeforeEach(func() { expectedErr = errors.New("got bananapants??") - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{}, expectedErr) }) @@ -102,7 +102,7 @@ var _ = Describe("run-task Command", func() { When("getting the current user does not return an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) diff --git a/command/v7/running_environment_variable_group_command.go b/command/v7/running_environment_variable_group_command.go index 9b782ce7cf9..9f36b48809e 100644 --- a/command/v7/running_environment_variable_group_command.go +++ b/command/v7/running_environment_variable_group_command.go @@ -18,7 +18,7 @@ func (cmd RunningEnvironmentVariableGroupCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/running_environment_variable_group_command_test.go b/command/v7/running_environment_variable_group_command_test.go index 8c652e57eda..7e259a60f5c 100644 --- a/command/v7/running_environment_variable_group_command_test.go +++ b/command/v7/running_environment_variable_group_command_test.go @@ -69,7 +69,7 @@ var _ = Describe("running-environment-variable-group Command", func() { When("the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "apple"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "apple"}, nil) }) It("should print text indicating its running", func() { diff --git a/command/v7/running_security_groups_command.go b/command/v7/running_security_groups_command.go index b3f84c84494..07969d0e485 100644 --- a/command/v7/running_security_groups_command.go +++ b/command/v7/running_security_groups_command.go @@ -17,7 +17,7 @@ func (cmd RunningSecurityGroupsCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/running_security_groups_command_test.go b/command/v7/running_security_groups_command_test.go index fcff0981938..dda4ab5ba08 100644 --- a/command/v7/running_security_groups_command_test.go +++ b/command/v7/running_security_groups_command_test.go @@ -63,7 +63,7 @@ var _ = Describe("Running Security Groups Command", func() { When("there are no globally enabled running security groups found", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{ Name: "some-user", }, @@ -88,7 +88,7 @@ var _ = Describe("Running Security Groups Command", func() { When("there are globally enabled running security groups", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) }) When("the security group does not have associated rules or spaces", func() { diff --git a/command/v7/scale_command.go b/command/v7/scale_command.go index 12e0bd9e789..fd0ed4f5469 100644 --- a/command/v7/scale_command.go +++ b/command/v7/scale_command.go @@ -29,7 +29,7 @@ func (cmd ScaleCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/scale_command_test.go b/command/v7/scale_command_test.go index 89abd07a942..0286c41ebfe 100644 --- a/command/v7/scale_command_test.go +++ b/command/v7/scale_command_test.go @@ -87,7 +87,7 @@ var _ = Describe("scale Command", func() { fakeConfig.TargetedSpaceReturns(configv3.Space{ GUID: "some-space-guid", Name: "some-space"}) - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) @@ -97,7 +97,7 @@ var _ = Describe("scale Command", func() { BeforeEach(func() { expectedErr = errors.New("getting current user error") - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{}, expectedErr) }) diff --git a/command/v7/security_group_command.go b/command/v7/security_group_command.go index 9d42e93b982..b264d4a0009 100644 --- a/command/v7/security_group_command.go +++ b/command/v7/security_group_command.go @@ -19,7 +19,7 @@ func (cmd SecurityGroupCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/security_group_command_test.go b/command/v7/security_group_command_test.go index a92b1842e43..faa3ddbabfd 100644 --- a/command/v7/security_group_command_test.go +++ b/command/v7/security_group_command_test.go @@ -65,7 +65,7 @@ var _ = Describe("Security Group Command", func() { When("getting the security group fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{ Name: "some-user", }, @@ -89,7 +89,7 @@ var _ = Describe("Security Group Command", func() { When("getting the security group succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org", GUID: "some-org-guid"}) }) diff --git a/command/v7/security_groups_command.go b/command/v7/security_groups_command.go index 13c721da2cf..b5b1442b794 100644 --- a/command/v7/security_groups_command.go +++ b/command/v7/security_groups_command.go @@ -17,7 +17,7 @@ func (cmd SecurityGroupsCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/security_groups_command_test.go b/command/v7/security_groups_command_test.go index 3674346b098..0d682e1f4c6 100644 --- a/command/v7/security_groups_command_test.go +++ b/command/v7/security_groups_command_test.go @@ -64,7 +64,7 @@ var _ = Describe("Security Groups Command", func() { When("getting the security groups fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{ Name: "some-user", }, @@ -88,7 +88,7 @@ var _ = Describe("Security Groups Command", func() { When("getting the security groups succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org", GUID: "some-org-guid"}) }) diff --git a/command/v7/service_access_command.go b/command/v7/service_access_command.go index acf93097c33..f61fb64ac3f 100644 --- a/command/v7/service_access_command.go +++ b/command/v7/service_access_command.go @@ -93,7 +93,7 @@ func accessFromVisibilityType(visibilityType string) string { } func (cmd ServiceAccessCommand) displayMessage() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/service_access_command_test.go b/command/v7/service_access_command_test.go index 574370392bd..0424f118218 100644 --- a/command/v7/service_access_command_test.go +++ b/command/v7/service_access_command_test.go @@ -44,7 +44,7 @@ var _ = Describe("service-access Command", func() { When("logged in", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeConfig.TargetReturns("some-url") }) @@ -178,14 +178,14 @@ var _ = Describe("service-access Command", func() { When("getting user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("fake get user error")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("fake get user error")) }) It("returns an error", func() { executeErr := cmd.Execute(nil) Expect(executeErr).To(MatchError("fake get user error")) - Expect(fakeConfig.CurrentUserCallCount()).To(Equal(1)) + Expect(fakeActor.GetCurrentUserCallCount()).To(Equal(1)) }) }) }) diff --git a/command/v7/service_brokers_command.go b/command/v7/service_brokers_command.go index bbf5ae14b41..4c36910b29b 100644 --- a/command/v7/service_brokers_command.go +++ b/command/v7/service_brokers_command.go @@ -18,7 +18,7 @@ func (cmd *ServiceBrokersCommand) Execute(args []string) error { return err } - currentUser, err := cmd.Config.CurrentUser() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/service_brokers_command_test.go b/command/v7/service_brokers_command_test.go index 2bf39910903..d4f35de0786 100644 --- a/command/v7/service_brokers_command_test.go +++ b/command/v7/service_brokers_command_test.go @@ -72,7 +72,7 @@ var _ = Describe("service-brokers Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { @@ -92,7 +92,7 @@ var _ = Describe("service-brokers Command", func() { GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) It("displays a message with the username", func() { diff --git a/command/v7/service_command.go b/command/v7/service_command.go index b6ed561737f..c528d7ae59f 100644 --- a/command/v7/service_command.go +++ b/command/v7/service_command.go @@ -98,7 +98,7 @@ func (cmd ServiceCommand) fetchAndDisplayDetails() error { } func (cmd ServiceCommand) displayIntro() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/service_command_test.go b/command/v7/service_command_test.go index 516339e5a20..5a0985311e5 100644 --- a/command/v7/service_command_test.go +++ b/command/v7/service_command_test.go @@ -54,7 +54,7 @@ var _ = Describe("service command", func() { }, } - fakeConfig.CurrentUserReturns(configv3.User{Name: username}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: username}, nil) fakeConfig.TargetedSpaceReturns(configv3.Space{ GUID: spaceGUID, diff --git a/command/v7/service_key_command.go b/command/v7/service_key_command.go index c6fa6fdcd21..9bb96a4007e 100644 --- a/command/v7/service_key_command.go +++ b/command/v7/service_key_command.go @@ -49,7 +49,7 @@ func (cmd ServiceKeyCommand) guid() error { } func (cmd ServiceKeyCommand) details() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/service_key_command_test.go b/command/v7/service_key_command_test.go index 3c98dac13b7..14710e52f85 100644 --- a/command/v7/service_key_command_test.go +++ b/command/v7/service_key_command_test.go @@ -68,7 +68,7 @@ var _ = Describe("service-key Command", func() { const fakeUserName = "fake-user-name" BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: fakeUserName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: fakeUserName}, nil) fakeActor.GetServiceKeyDetailsByServiceInstanceAndNameReturns( resources.ServiceCredentialBindingDetails{ @@ -102,7 +102,7 @@ var _ = Describe("service-key Command", func() { When("getting the username returns an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("bad thing")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("bad thing")) }) It("returns the error", func() { diff --git a/command/v7/service_keys_command.go b/command/v7/service_keys_command.go index fd95b32a46a..2d5c7f5affa 100644 --- a/command/v7/service_keys_command.go +++ b/command/v7/service_keys_command.go @@ -51,7 +51,7 @@ func (cmd ServiceKeysCommand) Examples() string { } func (cmd ServiceKeysCommand) displayIntro() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/service_keys_command_test.go b/command/v7/service_keys_command_test.go index a633cd5b781..7cd2fff5b62 100644 --- a/command/v7/service_keys_command_test.go +++ b/command/v7/service_keys_command_test.go @@ -48,7 +48,7 @@ var _ = Describe("service-keys Command", func() { fakeConfig.TargetedSpaceReturns(configv3.Space{GUID: fakeSpaceGUID}) - fakeConfig.CurrentUserReturns(configv3.User{Name: fakeUserName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: fakeUserName}, nil) fakeActor.GetServiceKeysByServiceInstanceReturns( []resources.ServiceCredentialBinding{ @@ -130,7 +130,7 @@ var _ = Describe("service-keys Command", func() { When("getting the username returns an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("bad thing")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("bad thing")) }) It("returns the error", func() { diff --git a/command/v7/services_command.go b/command/v7/services_command.go index c665037b4a0..a8c0df21f6b 100644 --- a/command/v7/services_command.go +++ b/command/v7/services_command.go @@ -41,7 +41,7 @@ func (cmd ServicesCommand) Usage() string { } func (cmd ServicesCommand) displayMessage() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/services_command_test.go b/command/v7/services_command_test.go index 8c76875be00..24ddaabf1b2 100644 --- a/command/v7/services_command_test.go +++ b/command/v7/services_command_test.go @@ -56,7 +56,7 @@ var _ = Describe("services command", func() { Name: org, }) - fakeConfig.CurrentUserReturns(configv3.User{Name: username}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: username}, nil) fakeActor.GetServiceInstancesForSpaceReturns( []v7action.ServiceInstance{ @@ -191,7 +191,7 @@ var _ = Describe("services command", func() { When("getting the user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("bang")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("bang")) }) It("fails", func() { diff --git a/command/v7/set_droplet_command.go b/command/v7/set_droplet_command.go index b9304be32b9..4528c1d6492 100644 --- a/command/v7/set_droplet_command.go +++ b/command/v7/set_droplet_command.go @@ -17,7 +17,7 @@ func (cmd SetDropletCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/set_droplet_command_test.go b/command/v7/set_droplet_command_test.go index a2b353b704c..3b1dcfb14e7 100644 --- a/command/v7/set_droplet_command_test.go +++ b/command/v7/set_droplet_command_test.go @@ -80,7 +80,7 @@ var _ = Describe("set-droplet Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { @@ -97,7 +97,7 @@ var _ = Describe("set-droplet Command", func() { Name: "some-space", GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) fakeActor.SetApplicationDropletByApplicationNameAndSpaceReturns(v7action.Warnings{"warning-1", "warning-2"}, nil) }) @@ -127,7 +127,7 @@ var _ = Describe("set-droplet Command", func() { fakeConfig.TargetedSpaceReturns(configv3.Space{ Name: "some-space", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) expectedErr = actionerror.ApplicationNotFoundError{Name: app} fakeActor.SetApplicationDropletByApplicationNameAndSpaceReturns(v7action.Warnings{"warning-1", "warning-2"}, expectedErr) }) diff --git a/command/v7/set_env_command.go b/command/v7/set_env_command.go index 0a3e739b30e..2dc01c88a44 100644 --- a/command/v7/set_env_command.go +++ b/command/v7/set_env_command.go @@ -19,7 +19,7 @@ func (cmd SetEnvCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/set_env_command_test.go b/command/v7/set_env_command_test.go index b3fec239d18..ef109a614b1 100644 --- a/command/v7/set_env_command_test.go +++ b/command/v7/set_env_command_test.go @@ -78,7 +78,7 @@ var _ = Describe("set-env Command", func() { When("getting the current user returns an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("some-error")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("some-error")) }) It("returns the error", func() { @@ -88,7 +88,7 @@ var _ = Describe("set-env Command", func() { When("getting the current user succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) }) When("setting the environment succeeds", func() { diff --git a/command/v7/set_health_check_command.go b/command/v7/set_health_check_command.go index e66dc875b92..83059b3d2d8 100644 --- a/command/v7/set_health_check_command.go +++ b/command/v7/set_health_check_command.go @@ -20,7 +20,7 @@ func (cmd SetHealthCheckCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/set_health_check_command_test.go b/command/v7/set_health_check_command_test.go index 83b872d9bd1..18c7451828c 100644 --- a/command/v7/set_health_check_command_test.go +++ b/command/v7/set_health_check_command_test.go @@ -65,7 +65,7 @@ var _ = Describe("set-health-check Command", func() { GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { @@ -92,7 +92,7 @@ var _ = Describe("set-health-check Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/set_org_default_isolation_segment_command.go b/command/v7/set_org_default_isolation_segment_command.go index df6b1342736..a19f517fa00 100644 --- a/command/v7/set_org_default_isolation_segment_command.go +++ b/command/v7/set_org_default_isolation_segment_command.go @@ -18,7 +18,7 @@ func (cmd SetOrgDefaultIsolationSegmentCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/set_org_default_isolation_segment_command_test.go b/command/v7/set_org_default_isolation_segment_command_test.go index 4ba665bc06e..982064c0a58 100644 --- a/command/v7/set_org_default_isolation_segment_command_test.go +++ b/command/v7/set_org_default_isolation_segment_command_test.go @@ -50,7 +50,7 @@ var _ = Describe("set-org-default-isolation-segment Command", func() { org = "some-org" isolationSegment = "segment1" - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) cmd.RequiredArgs.OrganizationName = org cmd.RequiredArgs.IsolationSegmentName = isolationSegment @@ -84,7 +84,7 @@ var _ = Describe("set-org-default-isolation-segment Command", func() { When("fetching the user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("some-error")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("some-error")) }) It("returns an error", func() { diff --git a/command/v7/set_org_quota_command.go b/command/v7/set_org_quota_command.go index 4d8734b0b39..2baad4c8efe 100644 --- a/command/v7/set_org_quota_command.go +++ b/command/v7/set_org_quota_command.go @@ -18,7 +18,7 @@ func (cmd *SetOrgQuotaCommand) Execute(args []string) error { return err } - currentUser, err := cmd.Config.CurrentUserName() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } @@ -26,7 +26,7 @@ func (cmd *SetOrgQuotaCommand) Execute(args []string) error { cmd.UI.DisplayTextWithFlavor("Setting quota {{.QuotaName}} to org {{.OrgName}} as {{.UserName}}...", map[string]interface{}{ "QuotaName": cmd.RequiredArgs.OrganizationQuota, "OrgName": cmd.RequiredArgs.Organization, - "UserName": currentUser, + "UserName": currentUser.Name, }) org, warnings, err := cmd.Actor.GetOrganizationByName(cmd.RequiredArgs.Organization) diff --git a/command/v7/set_org_quota_command_test.go b/command/v7/set_org_quota_command_test.go index 053ce3da626..88ac05c07f5 100644 --- a/command/v7/set_org_quota_command_test.go +++ b/command/v7/set_org_quota_command_test.go @@ -7,6 +7,7 @@ import ( "code.cloudfoundry.org/cli/command/flag" "code.cloudfoundry.org/cli/command/v7/v7fakes" "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/configv3" "code.cloudfoundry.org/cli/util/ui" . "code.cloudfoundry.org/cli/command/v7" @@ -53,7 +54,7 @@ var _ = Describe("set-org-quota Command", func() { fakeConfig.BinaryNameReturns(binaryName) currentUser = "current-user" - fakeConfig.CurrentUserNameReturns(currentUser, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: currentUser}, nil) fakeActor.GetOrganizationByNameReturns( resources.Organization{GUID: "some-org-guid"}, @@ -122,7 +123,7 @@ var _ = Describe("set-org-quota Command", func() { When("getting the current user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("", errors.New("current-user-error")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("current-user-error")) }) It("returns the error", func() { diff --git a/command/v7/set_org_role_command.go b/command/v7/set_org_role_command.go index 9756681e14a..a57ea353999 100644 --- a/command/v7/set_org_role_command.go +++ b/command/v7/set_org_role_command.go @@ -29,7 +29,7 @@ func (cmd *SetOrgRoleCommand) Execute(args []string) error { return err } - currentUser, err := cmd.Config.CurrentUser() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/set_org_role_command_test.go b/command/v7/set_org_role_command_test.go index 8fecc41923c..6c4ad32269b 100644 --- a/command/v7/set_org_role_command_test.go +++ b/command/v7/set_org_role_command_test.go @@ -56,7 +56,7 @@ var _ = Describe("set-org-role Command", func() { }) BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "current-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "current-user"}, nil) fakeActor.GetOrganizationByNameReturns( resources.Organization{GUID: "some-org-guid", Name: "some-org-name"}, diff --git a/command/v7/set_running_environment_variable_group_command.go b/command/v7/set_running_environment_variable_group_command.go index b2b93d806fe..c305199768d 100644 --- a/command/v7/set_running_environment_variable_group_command.go +++ b/command/v7/set_running_environment_variable_group_command.go @@ -24,7 +24,7 @@ func (cmd SetRunningEnvironmentVariableGroupCommand) Execute(args []string) erro return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/set_running_environment_variable_group_command_test.go b/command/v7/set_running_environment_variable_group_command_test.go index 81f649dafbd..a7e5b5d76ac 100644 --- a/command/v7/set_running_environment_variable_group_command_test.go +++ b/command/v7/set_running_environment_variable_group_command_test.go @@ -72,7 +72,7 @@ var _ = Describe("set-running-environment-variable-group Command", func() { When("the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "apple"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "apple"}, nil) }) It("should print text indicating its running", func() { diff --git a/command/v7/set_space_isolation_segment_command.go b/command/v7/set_space_isolation_segment_command.go index fa42aa98eea..53588995591 100644 --- a/command/v7/set_space_isolation_segment_command.go +++ b/command/v7/set_space_isolation_segment_command.go @@ -18,7 +18,7 @@ func (cmd SetSpaceIsolationSegmentCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/set_space_isolation_segment_command_test.go b/command/v7/set_space_isolation_segment_command_test.go index e34e72b9444..c6554154b83 100644 --- a/command/v7/set_space_isolation_segment_command_test.go +++ b/command/v7/set_space_isolation_segment_command_test.go @@ -71,7 +71,7 @@ var _ = Describe("set-space-isolation-segment Command", func() { When("the user is logged in", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{ Name: org, GUID: "some-org-guid", diff --git a/command/v7/set_space_quota_command.go b/command/v7/set_space_quota_command.go index 90a36af8e77..ab97cfabcd7 100644 --- a/command/v7/set_space_quota_command.go +++ b/command/v7/set_space_quota_command.go @@ -18,7 +18,7 @@ func (cmd *SetSpaceQuotaCommand) Execute(args []string) error { return err } - currentUser, err := cmd.Config.CurrentUserName() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } @@ -26,7 +26,7 @@ func (cmd *SetSpaceQuotaCommand) Execute(args []string) error { cmd.UI.DisplayTextWithFlavor("Setting space quota {{.QuotaName}} to space {{.SpaceName}} as {{.UserName}}...", map[string]interface{}{ "QuotaName": cmd.RequiredArgs.SpaceQuota, "SpaceName": cmd.RequiredArgs.Space, - "UserName": currentUser, + "UserName": currentUser.Name, }) org := cmd.Config.TargetedOrganization() diff --git a/command/v7/set_space_quota_command_test.go b/command/v7/set_space_quota_command_test.go index dd9c40c0ef2..e94e62f841e 100644 --- a/command/v7/set_space_quota_command_test.go +++ b/command/v7/set_space_quota_command_test.go @@ -73,7 +73,7 @@ var _ = Describe("set-space-quota Command", func() { fakeConfig.BinaryNameReturns(binaryName) currentUser = "current-user" - fakeConfig.CurrentUserNameReturns(currentUser, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: currentUser}, nil) fakeConfig.TargetedOrganizationReturns(org) diff --git a/command/v7/set_space_role_command.go b/command/v7/set_space_role_command.go index f23d45b853b..77ba20ced8b 100644 --- a/command/v7/set_space_role_command.go +++ b/command/v7/set_space_role_command.go @@ -31,7 +31,7 @@ func (cmd *SetSpaceRoleCommand) Execute(args []string) error { return err } - currentUser, err := cmd.Config.CurrentUser() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/set_space_role_command_test.go b/command/v7/set_space_role_command_test.go index 6b9cd1249e8..ac29113070d 100644 --- a/command/v7/set_space_role_command_test.go +++ b/command/v7/set_space_role_command_test.go @@ -56,7 +56,7 @@ var _ = Describe("set-space-role Command", func() { }) BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "current-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "current-user"}, nil) fakeActor.GetOrganizationByNameReturns( resources.Organization{ diff --git a/command/v7/set_staging_environment_variable_group_command.go b/command/v7/set_staging_environment_variable_group_command.go index 84a6bac78f8..20cd146d30f 100644 --- a/command/v7/set_staging_environment_variable_group_command.go +++ b/command/v7/set_staging_environment_variable_group_command.go @@ -24,7 +24,7 @@ func (cmd SetStagingEnvironmentVariableGroupCommand) Execute(args []string) erro return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/set_staging_environment_variable_group_command_test.go b/command/v7/set_staging_environment_variable_group_command_test.go index 28c4ba853b5..511a8df6616 100644 --- a/command/v7/set_staging_environment_variable_group_command_test.go +++ b/command/v7/set_staging_environment_variable_group_command_test.go @@ -72,7 +72,7 @@ var _ = Describe("set-staging-environment-variable-group Command", func() { When("the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "apple"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "apple"}, nil) }) It("should print text indicating its running", func() { diff --git a/command/v7/share_private_domain_command.go b/command/v7/share_private_domain_command.go index 66bb9c95b9f..2ba4f0a8612 100644 --- a/command/v7/share_private_domain_command.go +++ b/command/v7/share_private_domain_command.go @@ -18,7 +18,7 @@ func (cmd SharePrivateDomainCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/share_private_domain_command_test.go b/command/v7/share_private_domain_command_test.go index c1bb263b130..6d01497b177 100644 --- a/command/v7/share_private_domain_command_test.go +++ b/command/v7/share_private_domain_command_test.go @@ -75,7 +75,7 @@ var _ = Describe("share-private-domain command", func() { When("getting the current user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("current-user-error")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("current-user-error")) }) It("returns an error", func() { @@ -90,7 +90,7 @@ var _ = Describe("share-private-domain command", func() { When("the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "the-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "the-user"}, nil) }) It("should print text indicating it is sharing a domain", func() { diff --git a/command/v7/share_service_command.go b/command/v7/share_service_command.go index ef9a1fd018a..fdf72c1ad50 100644 --- a/command/v7/share_service_command.go +++ b/command/v7/share_service_command.go @@ -48,7 +48,7 @@ func (cmd ShareServiceCommand) Execute(args []string) error { } func (cmd ShareServiceCommand) displayIntro() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/share_service_command_test.go b/command/v7/share_service_command_test.go index 27f43cc65b2..46fd5a8f349 100644 --- a/command/v7/share_service_command_test.go +++ b/command/v7/share_service_command_test.go @@ -85,7 +85,7 @@ var _ = Describe("share-service command", func() { fakeSharedActor.CheckTargetReturns(nil) fakeConfig.TargetedSpaceReturns(configv3.Space{GUID: expectedTargetedSpaceGuid}) fakeConfig.TargetedOrganizationReturns(configv3.Organization{GUID: expectedTargetedOrgGuid, Name: expectedTargetedOrgName}) - fakeConfig.CurrentUserReturns(configv3.User{Name: expectedUser}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: expectedUser}, nil) }) When("the share completes successfully", func() { @@ -167,7 +167,7 @@ var _ = Describe("share-service command", func() { When("getting the username fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("boom")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("boom")) }) It("returns the error", func() { diff --git a/command/v7/shared/app_stager.go b/command/v7/shared/app_stager.go index 2f5e73ad4e0..a94f168a9ae 100644 --- a/command/v7/shared/app_stager.go +++ b/command/v7/shared/app_stager.go @@ -58,6 +58,7 @@ type Stager struct { type stagingAndStartActor interface { CreateDeploymentByApplicationAndDroplet(appGUID string, dropletGUID string) (string, v7action.Warnings, error) CreateDeploymentByApplicationAndRevision(appGUID string, revisionGUID string) (string, v7action.Warnings, error) + GetCurrentUser() (configv3.User, error) GetDetailedAppSummary(appName string, spaceGUID string, withObfuscatedValues bool) (v7action.DetailedApplicationSummary, v7action.Warnings, error) GetStreamingLogsForApplicationByNameAndSpace(appName string, spaceGUID string, client sharedaction.LogCacheClient) (<-chan sharedaction.LogMessage, <-chan error, context.CancelFunc, v7action.Warnings, error) PollStart(app resources.Application, noWait bool, handleProcessStats func(string)) (v7action.Warnings, error) @@ -172,7 +173,7 @@ func (stager *Stager) StartApp( return err } } else { - user, err := stager.Config.CurrentUser() + user, err := stager.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/shared/app_stager_test.go b/command/v7/shared/app_stager_test.go index 079c4736616..0650715bbea 100644 --- a/command/v7/shared/app_stager_test.go +++ b/command/v7/shared/app_stager_test.go @@ -121,7 +121,7 @@ var _ = Describe("app stager", func() { Expect(executeErr).ToNot(HaveOccurred()) Expect(testUI.Out).To(Say("Staging app and tracing logs...")) - user, err := fakeConfig.CurrentUser() + user, err := fakeActor.GetCurrentUser() Expect(err).NotTo(HaveOccurred()) Expect(testUI.Out).To(Say(`Restarting app %s in org %s / space %s as %s\.\.\.`, app.Name, organization.Name, space.Name, user.Name)) Expect(testUI.Out).To(Say("Waiting for app to start...")) @@ -330,7 +330,7 @@ var _ = Describe("app stager", func() { organization = configv3.Organization{Name: "some-org"} resourceGUID = "droplet-guid" - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) fakeActor.GetDetailedAppSummaryReturns(v7action.DetailedApplicationSummary{}, v7action.Warnings{"application-summary-warning-1", "application-summary-warning-2"}, nil) }) @@ -456,7 +456,7 @@ var _ = Describe("app stager", func() { It("displays output for each step of starting", func() { Expect(executeErr).To(BeNil()) - user, err := fakeConfig.CurrentUser() + user, err := fakeActor.GetCurrentUser() Expect(err).NotTo(HaveOccurred()) Expect(testUI.Out).To(Say(`Starting app %s in org %s / space %s as %s\.\.\.`, app.Name, organization.Name, space.Name, user.Name)) @@ -490,7 +490,7 @@ var _ = Describe("app stager", func() { It("displays output for each step of restarting", func() { Expect(executeErr).To(BeNil()) - user, err := fakeConfig.CurrentUser() + user, err := fakeActor.GetCurrentUser() Expect(err).NotTo(HaveOccurred()) Expect(testUI.Out).To(Say(`Restarting app %s in org %s / space %s as %s\.\.\.`, app.Name, organization.Name, space.Name, user.Name)) diff --git a/command/v7/shared/new_clients.go b/command/v7/shared/new_clients.go index c919b29094a..4486bd8ffab 100644 --- a/command/v7/shared/new_clients.go +++ b/command/v7/shared/new_clients.go @@ -1,6 +1,7 @@ package shared import ( + "code.cloudfoundry.org/cli/actor/v7action" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" ccWrapper "code.cloudfoundry.org/cli/api/cloudcontroller/wrapper" "code.cloudfoundry.org/cli/api/router" @@ -14,24 +15,27 @@ import ( func GetNewClientsAndConnectToCF(config command.Config, ui command.UI, minVersionV3 string) (*ccv3.Client, *uaa.Client, *router.Client, error) { var err error - ccClient, authWrapper := NewWrappedCloudControllerClient(config, ui) - - ccClient, err = connectToCF(config, ui, ccClient, minVersionV3) + uaaClient, err := newWrappedUAAClient(config, ui) if err != nil { return nil, nil, nil, err } - uaaClient, err := newWrappedUAAClient(config, ui, ccClient, authWrapper) + routingClient, err := newWrappedRoutingClient(config, ui, uaaClient) if err != nil { return nil, nil, nil, err } - routingClient, err := newWrappedRoutingClient(config, ui, uaaClient) + ccClient := NewAuthWrappedCloudControllerClient(config, ui, uaaClient) + + ccClient, err = connectToCF(config, ui, ccClient, minVersionV3) + if err != nil { + return nil, nil, nil, err + } return ccClient, uaaClient, routingClient, err } -func NewWrappedCloudControllerClient(config command.Config, ui command.UI) (*ccv3.Client, *ccWrapper.UAAAuthentication) { +func NewWrappedCloudControllerClient(config command.Config, ui command.UI, extraWrappers ...ccv3.ConnectionWrapper) *ccv3.Client { ccWrappers := []ccv3.ConnectionWrapper{} verbose, location := config.Verbose() @@ -42,22 +46,32 @@ func NewWrappedCloudControllerClient(config command.Config, ui command.UI) (*ccv ccWrappers = append(ccWrappers, ccWrapper.NewRequestLogger(ui.RequestLoggerFileWriter(location))) } - authWrapper := ccWrapper.NewUAAAuthentication(nil, config) - - ccWrappers = append(ccWrappers, authWrapper) + ccWrappers = append(ccWrappers, extraWrappers...) ccWrappers = append(ccWrappers, ccWrapper.NewRetryRequest(config.RequestRetryCount())) - ccClient := ccv3.NewClient(ccv3.Config{ + return ccv3.NewClient(ccv3.Config{ AppName: config.BinaryName(), AppVersion: config.BinaryVersion(), JobPollingTimeout: config.OverallPollingTimeout(), JobPollingInterval: config.PollingInterval(), Wrappers: ccWrappers, }) - return ccClient, authWrapper } -func newWrappedUAAClient(config command.Config, ui command.UI, ccClient *ccv3.Client, authWrapper *ccWrapper.UAAAuthentication) (*uaa.Client, error) { +func NewAuthWrappedCloudControllerClient(config command.Config, ui command.UI, uaaClient *uaa.Client) *ccv3.Client { + var authWrapper ccv3.ConnectionWrapper + authWrapper = ccWrapper.NewUAAAuthentication(uaaClient, config) + if config.IsCFOnK8s() { + authWrapper = ccWrapper.NewKubernetesAuthentication( + config, + v7action.NewDefaultKubernetesConfigGetter(), + ) + } + + return NewWrappedCloudControllerClient(config, ui, authWrapper) +} + +func newWrappedUAAClient(config command.Config, ui command.UI) (*uaa.Client, error) { var err error verbose, location := config.Verbose() @@ -78,9 +92,6 @@ func newWrappedUAAClient(config command.Config, ui command.UI, ccClient *ccv3.Cl return nil, err } - uaaAuthWrapper.SetClient(uaaClient) - authWrapper.SetClient(uaaClient) - return uaaClient, nil } diff --git a/command/v7/shared/new_clients_test.go b/command/v7/shared/new_clients_test.go index 71d16c1b289..04bb1ec4b87 100644 --- a/command/v7/shared/new_clients_test.go +++ b/command/v7/shared/new_clients_test.go @@ -58,9 +58,8 @@ var _ = Describe("New Clients", func() { }) When("not targetting", func() { - It("does not target and returns no UAA client", func() { - ccClient, authWrapper := NewWrappedCloudControllerClient(fakeConfig, testUI) - Expect(authWrapper).ToNot(BeNil()) + It("does not target", func() { + ccClient := NewWrappedCloudControllerClient(fakeConfig, testUI) Expect(ccClient).ToNot(BeNil()) Expect(fakeConfig.SkipSSLValidationCallCount()).To(Equal(0)) }) diff --git a/command/v7/shared/package_displayer.go b/command/v7/shared/package_displayer.go index 73ed36df804..615c851102f 100644 --- a/command/v7/shared/package_displayer.go +++ b/command/v7/shared/package_displayer.go @@ -16,7 +16,7 @@ func NewPackageDisplayer(ui command.UI, config command.Config) PackageDisplayer } } -func (display PackageDisplayer) DisplaySetupMessage(appName string, isDockerImage bool) error { +func (display PackageDisplayer) DisplaySetupMessage(appName, currentUser string, isDockerImage bool) error { var flavorTextTemplate string if isDockerImage { flavorTextTemplate = "Creating docker package for app {{.AppName}} in org {{.CurrentOrg}} / space {{.CurrentSpace}} as {{.CurrentUser}}..." @@ -24,15 +24,11 @@ func (display PackageDisplayer) DisplaySetupMessage(appName string, isDockerImag flavorTextTemplate = "Creating and uploading bits package for app {{.AppName}} in org {{.CurrentOrg}} / space {{.CurrentSpace}} as {{.CurrentUser}}..." } - currentUser, err := display.config.CurrentUser() - if err != nil { - return err - } display.ui.DisplayTextWithFlavor(flavorTextTemplate, map[string]interface{}{ "AppName": appName, "CurrentSpace": display.config.TargetedSpace().Name, "CurrentOrg": display.config.TargetedOrganization().Name, - "CurrentUser": currentUser.Name, + "CurrentUser": currentUser, }) return nil diff --git a/command/v7/space_command.go b/command/v7/space_command.go index 3fbc2b42c9a..cf5d52ea7d3 100644 --- a/command/v7/space_command.go +++ b/command/v7/space_command.go @@ -33,7 +33,7 @@ func (cmd SpaceCommand) Execute(args []string) error { return cmd.displaySpaceGUID(spaceName, targetedOrg.GUID) } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/space_command_test.go b/command/v7/space_command_test.go index 613e9888dfd..5f2a9cbd0fc 100644 --- a/command/v7/space_command_test.go +++ b/command/v7/space_command_test.go @@ -55,7 +55,7 @@ var _ = Describe("space command", func() { GUID: "some-org-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { @@ -82,7 +82,7 @@ var _ = Describe("space command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/space_quota_command.go b/command/v7/space_quota_command.go index 81b3d6188f7..8cbdcc2d45d 100644 --- a/command/v7/space_quota_command.go +++ b/command/v7/space_quota_command.go @@ -20,7 +20,7 @@ func (cmd SpaceQuotaCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/space_quota_command_test.go b/command/v7/space_quota_command_test.go index 5bb7233b4a6..ce15a9c9fc4 100644 --- a/command/v7/space_quota_command_test.go +++ b/command/v7/space_quota_command_test.go @@ -66,7 +66,7 @@ var _ = Describe("Space Quota Command", func() { When("getting the space quota fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{ Name: "some-user", }, @@ -90,7 +90,7 @@ var _ = Describe("Space Quota Command", func() { When("getting the space quota succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org", GUID: "some-org-guid"}) falseValue := false diff --git a/command/v7/space_quotas_command.go b/command/v7/space_quotas_command.go index addfd2b44ec..481cd6c61f5 100644 --- a/command/v7/space_quotas_command.go +++ b/command/v7/space_quotas_command.go @@ -18,7 +18,7 @@ func (cmd SpaceQuotasCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/space_quotas_command_test.go b/command/v7/space_quotas_command_test.go index 8782f364d7e..c0626293045 100644 --- a/command/v7/space_quotas_command_test.go +++ b/command/v7/space_quotas_command_test.go @@ -60,7 +60,7 @@ var _ = Describe("space-quotas command", func() { When("running the command successfully", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "apple"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "apple"}, nil) spaceQuotas := []resources.SpaceQuota{ { Quota: resources.Quota{ @@ -167,7 +167,7 @@ var _ = Describe("space-quotas command", func() { When("the quota list is empty", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "apple"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "apple"}, nil) fakeActor.GetSpaceQuotasByOrgGUIDReturns([]resources.SpaceQuota{}, v7action.Warnings{"some-warning-1", "some-warning-2"}, nil) }) diff --git a/command/v7/space_users_command.go b/command/v7/space_users_command.go index 9ab01a0c8cc..d17029ec03c 100644 --- a/command/v7/space_users_command.go +++ b/command/v7/space_users_command.go @@ -21,7 +21,7 @@ func (cmd *SpaceUsersCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/space_users_command_test.go b/command/v7/space_users_command_test.go index 1d637378865..58b96fbca69 100644 --- a/command/v7/space_users_command_test.go +++ b/command/v7/space_users_command_test.go @@ -75,7 +75,7 @@ var _ = Describe("space-users Command", func() { When("getting the current user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("get-current-user-error")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("get-current-user-error")) }) It("returns the error", func() { @@ -85,7 +85,7 @@ var _ = Describe("space-users Command", func() { When("getting the current user succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) diff --git a/command/v7/spaces_command.go b/command/v7/spaces_command.go index b3db2a42e2c..430c264dba6 100644 --- a/command/v7/spaces_command.go +++ b/command/v7/spaces_command.go @@ -19,7 +19,7 @@ func (cmd SpacesCommand) Execute([]string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/spaces_command_test.go b/command/v7/spaces_command_test.go index af8acecb4ec..bd2a53bc1ab 100644 --- a/command/v7/spaces_command_test.go +++ b/command/v7/spaces_command_test.go @@ -75,7 +75,7 @@ var _ = Describe("spaces Command", func() { When("getting the current user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("get-user-error")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("get-user-error")) }) It("returns the error", func() { @@ -85,7 +85,7 @@ var _ = Describe("spaces Command", func() { When("getting the current user succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) diff --git a/command/v7/ssh_enabled_command_test.go b/command/v7/ssh_enabled_command_test.go index ce168503255..abcd806db66 100644 --- a/command/v7/ssh_enabled_command_test.go +++ b/command/v7/ssh_enabled_command_test.go @@ -8,6 +8,7 @@ import ( "code.cloudfoundry.org/cli/command/commandfakes" . "code.cloudfoundry.org/cli/command/v7" "code.cloudfoundry.org/cli/command/v7/v7fakes" + "code.cloudfoundry.org/cli/util/configv3" "code.cloudfoundry.org/cli/util/ui" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -49,7 +50,7 @@ var _ = Describe("ssh-enabled Command", func() { binaryName = "faceman" fakeConfig.BinaryNameReturns(binaryName) currentUserName = "some-user" - fakeConfig.CurrentUserNameReturns(currentUserName, nil) + fakeSSHEnabledActor.GetCurrentUserReturns(configv3.User{Name: currentUserName}, nil) }) JustBeforeEach(func() { diff --git a/command/v7/stack_command.go b/command/v7/stack_command.go index bb10ffd456b..a7ca6add762 100644 --- a/command/v7/stack_command.go +++ b/command/v7/stack_command.go @@ -44,7 +44,7 @@ func (cmd *StackCommand) displayStackGUID() error { } func (cmd *StackCommand) displayStackInfo() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/stack_command_test.go b/command/v7/stack_command_test.go index df528bf1dc9..c7127c3b589 100644 --- a/command/v7/stack_command_test.go +++ b/command/v7/stack_command_test.go @@ -77,7 +77,7 @@ var _ = Describe("Stack Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { @@ -90,7 +90,7 @@ var _ = Describe("Stack Command", func() { BeforeEach(func() { fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "some-space", GUID: "some-space-guid"}) fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org"}) - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) }) Context("When the stack exists", func() { diff --git a/command/v7/stacks_command.go b/command/v7/stacks_command.go index ea91ef5c3a9..0e4b7926331 100644 --- a/command/v7/stacks_command.go +++ b/command/v7/stacks_command.go @@ -22,7 +22,7 @@ func (cmd StacksCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/stacks_command_test.go b/command/v7/stacks_command_test.go index 75533edbdbc..dff97b6ee03 100644 --- a/command/v7/stacks_command_test.go +++ b/command/v7/stacks_command_test.go @@ -74,7 +74,7 @@ var _ = Describe("stacks Command", func() { Context("When the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) }) When("StacksActor returns an error", func() { diff --git a/command/v7/stage_package_command.go b/command/v7/stage_package_command.go index 37712be8222..729f497461b 100644 --- a/command/v7/stage_package_command.go +++ b/command/v7/stage_package_command.go @@ -41,7 +41,7 @@ func (cmd StagePackageCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/stage_package_command_test.go b/command/v7/stage_package_command_test.go index f546d325cf5..a1906806f47 100644 --- a/command/v7/stage_package_command_test.go +++ b/command/v7/stage_package_command_test.go @@ -81,7 +81,7 @@ var _ = Describe("stage-package Command", func() { GUID: spaceGUID, Name: "some-space", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) allLogsWritten = make(chan bool) fakeActor.GetStreamingLogsForApplicationByNameAndSpaceStub = func(appName string, spaceGUID string, client sharedaction.LogCacheClient) (<-chan sharedaction.LogMessage, <-chan error, context.CancelFunc, v7action.Warnings, error) { diff --git a/command/v7/staging_environment_variable_group_command.go b/command/v7/staging_environment_variable_group_command.go index bcfea5b9d9a..3746e7a458d 100644 --- a/command/v7/staging_environment_variable_group_command.go +++ b/command/v7/staging_environment_variable_group_command.go @@ -19,7 +19,7 @@ func (cmd StagingEnvironmentVariableGroupCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/staging_environment_variable_group_command_test.go b/command/v7/staging_environment_variable_group_command_test.go index 1aa710988c6..9ecf27e568a 100644 --- a/command/v7/staging_environment_variable_group_command_test.go +++ b/command/v7/staging_environment_variable_group_command_test.go @@ -69,7 +69,7 @@ var _ = Describe("staging-environment-variable-group Command", func() { When("the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "apple"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "apple"}, nil) }) It("should print text indicating its running", func() { diff --git a/command/v7/staging_security_groups_command.go b/command/v7/staging_security_groups_command.go index f9cb0137f15..8b4203eb577 100644 --- a/command/v7/staging_security_groups_command.go +++ b/command/v7/staging_security_groups_command.go @@ -17,7 +17,7 @@ func (cmd StagingSecurityGroupsCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/staging_security_groups_command_test.go b/command/v7/staging_security_groups_command_test.go index 9efc4847b12..c0fe38d6f07 100644 --- a/command/v7/staging_security_groups_command_test.go +++ b/command/v7/staging_security_groups_command_test.go @@ -63,7 +63,7 @@ var _ = Describe("Staging Security Groups Command", func() { When("there are no globally enabled staging security groups found", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{ Name: "some-user", }, @@ -88,7 +88,7 @@ var _ = Describe("Staging Security Groups Command", func() { When("there are globally enabled staging security groups", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil) }) When("the security group does not have associated rules or spaces", func() { diff --git a/command/v7/start_command.go b/command/v7/start_command.go index 79b3589b8ec..23271215110 100644 --- a/command/v7/start_command.go +++ b/command/v7/start_command.go @@ -39,7 +39,7 @@ func (cmd StartCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/start_command_test.go b/command/v7/start_command_test.go index 8e3f67cbf58..24ec6f7b185 100644 --- a/command/v7/start_command_test.go +++ b/command/v7/start_command_test.go @@ -54,7 +54,7 @@ var _ = Describe("start Command", func() { Name: "some-space", GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) fakeActor.GetApplicationByNameAndSpaceReturns(app, v7action.Warnings{"get-app-warning"}, nil) cmd = v7.StartCommand{ @@ -94,7 +94,7 @@ var _ = Describe("start Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/stop_command.go b/command/v7/stop_command.go index c7ee62b5809..514f1ecba58 100644 --- a/command/v7/stop_command.go +++ b/command/v7/stop_command.go @@ -18,7 +18,7 @@ func (cmd StopCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/stop_command_test.go b/command/v7/stop_command_test.go index 189287a233d..18efa1d4de7 100644 --- a/command/v7/stop_command_test.go +++ b/command/v7/stop_command_test.go @@ -80,7 +80,7 @@ var _ = Describe("stop Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { @@ -97,7 +97,7 @@ var _ = Describe("stop Command", func() { Name: "some-space", GUID: "some-space-guid", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) fakeActor.GetApplicationByNameAndSpaceReturns(resources.Application{GUID: "some-app-guid", State: constant.ApplicationStarted}, v7action.Warnings{"get-warning-1", "get-warning-2"}, nil) fakeActor.StopApplicationReturns(v7action.Warnings{"stop-warning-1", "stop-warning-2"}, nil) }) @@ -129,7 +129,7 @@ var _ = Describe("stop Command", func() { fakeConfig.TargetedSpaceReturns(configv3.Space{ Name: "some-space", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) expectedErr = actionerror.ApplicationNotFoundError{Name: app} fakeActor.GetApplicationByNameAndSpaceReturns(resources.Application{State: constant.ApplicationStarted}, v7action.Warnings{"get-warning-1", "get-warning-2"}, expectedErr) }) @@ -153,7 +153,7 @@ var _ = Describe("stop Command", func() { fakeConfig.TargetedSpaceReturns(configv3.Space{ Name: "some-space", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) fakeActor.GetApplicationByNameAndSpaceReturns(resources.Application{State: constant.ApplicationStarted}, v7action.Warnings{"get-warning-1", "get-warning-2"}, nil) expectedErr = actionerror.ApplicationNotFoundError{Name: app} fakeActor.StopApplicationReturns(v7action.Warnings{"stop-warning-1", "stop-warning-2"}, expectedErr) @@ -178,7 +178,7 @@ var _ = Describe("stop Command", func() { fakeConfig.TargetedSpaceReturns(configv3.Space{ Name: "some-space", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) fakeActor.GetApplicationByNameAndSpaceReturns(resources.Application{State: constant.ApplicationStopped}, v7action.Warnings{"get-warning-1", "get-warning-2"}, nil) }) @@ -205,7 +205,7 @@ var _ = Describe("stop Command", func() { fakeConfig.TargetedSpaceReturns(configv3.Space{ Name: "some-space", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) expectedErr = errors.New("some-error") fakeActor.GetApplicationByNameAndSpaceReturns(resources.Application{State: constant.ApplicationStarted}, v7action.Warnings{"get-warning-1", "get-warning-2"}, expectedErr) }) @@ -231,7 +231,7 @@ var _ = Describe("stop Command", func() { fakeConfig.TargetedSpaceReturns(configv3.Space{ Name: "some-space", }) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) fakeActor.GetApplicationByNameAndSpaceReturns(resources.Application{State: constant.ApplicationStarted}, v7action.Warnings{"get-warning-1", "get-warning-2"}, nil) expectedErr = errors.New("some-error") fakeActor.StopApplicationReturns(v7action.Warnings{"stop-warning-1", "stop-warning-2"}, expectedErr) diff --git a/command/v7/target_command.go b/command/v7/target_command.go index edc565e3cdc..05595ca294a 100644 --- a/command/v7/target_command.go +++ b/command/v7/target_command.go @@ -22,7 +22,7 @@ func (cmd *TargetCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { cmd.clearTargets() return err diff --git a/command/v7/target_command_test.go b/command/v7/target_command_test.go index 765a03350b5..3d245ad0899 100644 --- a/command/v7/target_command_test.go +++ b/command/v7/target_command_test.go @@ -88,7 +88,7 @@ var _ = Describe("target Command", func() { BeforeEach(func() { someErr = errors.New("some-current-user-error") - fakeConfig.CurrentUserReturns(configv3.User{}, someErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, someErr) }) It("returns the same error", func() { @@ -101,7 +101,7 @@ var _ = Describe("target Command", func() { When("getting the current user does not return an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) diff --git a/command/v7/tasks_command.go b/command/v7/tasks_command.go index 2a8e49dd00f..9c3cf8fcdf6 100644 --- a/command/v7/tasks_command.go +++ b/command/v7/tasks_command.go @@ -25,7 +25,7 @@ func (cmd TasksCommand) Execute(args []string) error { space := cmd.Config.TargetedSpace() - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/tasks_command_test.go b/command/v7/tasks_command_test.go index 632dd3e04c2..aeccd989a18 100644 --- a/command/v7/tasks_command_test.go +++ b/command/v7/tasks_command_test.go @@ -88,7 +88,7 @@ var _ = Describe("tasks Command", func() { BeforeEach(func() { expectedErr = errors.New("get current user error") - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{}, expectedErr) }) @@ -100,7 +100,7 @@ var _ = Describe("tasks Command", func() { When("getting the current user does not return an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) diff --git a/command/v7/terminate_task_command.go b/command/v7/terminate_task_command.go index b1b2cd5bc11..0099980f16c 100644 --- a/command/v7/terminate_task_command.go +++ b/command/v7/terminate_task_command.go @@ -33,7 +33,7 @@ func (cmd TerminateTaskCommand) Execute(args []string) error { space := cmd.Config.TargetedSpace() - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/terminate_task_command_test.go b/command/v7/terminate_task_command_test.go index 626b5f9bb11..5528bf0fa66 100644 --- a/command/v7/terminate_task_command_test.go +++ b/command/v7/terminate_task_command_test.go @@ -102,7 +102,7 @@ var _ = Describe("terminate-task Command", func() { BeforeEach(func() { expectedErr = errors.New("get current user error") - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{}, expectedErr) }) @@ -114,7 +114,7 @@ var _ = Describe("terminate-task Command", func() { When("getting the current user does not return an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) diff --git a/command/v7/unbind_route_service_command.go b/command/v7/unbind_route_service_command.go index 2e012ffa950..d973dc6c48b 100644 --- a/command/v7/unbind_route_service_command.go +++ b/command/v7/unbind_route_service_command.go @@ -95,7 +95,7 @@ func (cmd UnbindRouteServiceCommand) displayPrompt() (bool, error) { } func (cmd UnbindRouteServiceCommand) displayIntro() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/unbind_route_service_command_test.go b/command/v7/unbind_route_service_command_test.go index f9cf32a4be6..4b0c5e6044f 100644 --- a/command/v7/unbind_route_service_command_test.go +++ b/command/v7/unbind_route_service_command_test.go @@ -62,7 +62,7 @@ var _ = Describe("unbind-route-service Command", func() { fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: fakeOrgName}) - fakeConfig.CurrentUserReturns(configv3.User{Name: fakeUserName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: fakeUserName}, nil) fakeActor.DeleteRouteBindingReturns( nil, @@ -452,7 +452,7 @@ var _ = Describe("unbind-route-service Command", func() { When("getting the username returns an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("bad thing")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("bad thing")) }) It("returns the error", func() { diff --git a/command/v7/unbind_running_group_command_test.go b/command/v7/unbind_running_group_command_test.go index 7f921dbccb7..cef38fad9c6 100644 --- a/command/v7/unbind_running_group_command_test.go +++ b/command/v7/unbind_running_group_command_test.go @@ -46,7 +46,7 @@ var _ = Describe("unbind-running-security-group Command", func() { cmd.RequiredArgs.SecurityGroup = "some-security-group" - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) diff --git a/command/v7/unbind_running_security_group_command.go b/command/v7/unbind_running_security_group_command.go index 4f0ad46beb4..264a4ab86cd 100644 --- a/command/v7/unbind_running_security_group_command.go +++ b/command/v7/unbind_running_security_group_command.go @@ -22,7 +22,7 @@ func (cmd UnbindRunningSecurityGroupCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/unbind_security_group.go b/command/v7/unbind_security_group.go index b74e0290864..9bc55399cc8 100644 --- a/command/v7/unbind_security_group.go +++ b/command/v7/unbind_security_group.go @@ -29,7 +29,7 @@ func (cmd UnbindSecurityGroupCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/unbind_security_group_test.go b/command/v7/unbind_security_group_test.go index 06c25749d0c..4af1a6edb30 100644 --- a/command/v7/unbind_security_group_test.go +++ b/command/v7/unbind_security_group_test.go @@ -52,7 +52,7 @@ var _ = Describe("unbind-security-group Command", func() { fakeConfig.BinaryNameReturns(binaryName) fakeConfig.ExperimentalReturns(true) - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) fakeActor.UnbindSecurityGroupReturns( @@ -84,7 +84,7 @@ var _ = Describe("unbind-security-group Command", func() { When("getting the current user fails", func() { BeforeEach(func() { expectedErr = errors.New("getting user failed") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("returns an error", func() { diff --git a/command/v7/unbind_service_command.go b/command/v7/unbind_service_command.go index 660cc38c622..ccf2f134fd7 100644 --- a/command/v7/unbind_service_command.go +++ b/command/v7/unbind_service_command.go @@ -61,7 +61,7 @@ func (cmd UnbindServiceCommand) Usage() string { } func (cmd UnbindServiceCommand) displayIntro() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/unbind_service_command_test.go b/command/v7/unbind_service_command_test.go index f2779f0871c..686708b3761 100644 --- a/command/v7/unbind_service_command_test.go +++ b/command/v7/unbind_service_command_test.go @@ -56,7 +56,7 @@ var _ = Describe("unbind-service Command", func() { fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: fakeOrgName}) - fakeConfig.CurrentUserReturns(configv3.User{Name: fakeUserName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: fakeUserName}, nil) fakeActor.DeleteServiceAppBindingReturns( nil, @@ -305,7 +305,7 @@ var _ = Describe("unbind-service Command", func() { When("getting the username returns an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("bad thing")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("bad thing")) }) It("returns the error", func() { diff --git a/command/v7/unbind_staging_security_group_command.go b/command/v7/unbind_staging_security_group_command.go index 69463f693a1..3734ed62483 100644 --- a/command/v7/unbind_staging_security_group_command.go +++ b/command/v7/unbind_staging_security_group_command.go @@ -22,7 +22,7 @@ func (cmd UnbindStagingSecurityGroupCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/unbind_staging_security_group_command_test.go b/command/v7/unbind_staging_security_group_command_test.go index af9e3e0d7fc..7588628cc73 100644 --- a/command/v7/unbind_staging_security_group_command_test.go +++ b/command/v7/unbind_staging_security_group_command_test.go @@ -46,7 +46,7 @@ var _ = Describe("unbind-staging-security-group Command", func() { cmd.RequiredArgs.SecurityGroup = "some-security-group" - fakeConfig.CurrentUserReturns( + fakeActor.GetCurrentUserReturns( configv3.User{Name: "some-user"}, nil) }) diff --git a/command/v7/unmap_route_command.go b/command/v7/unmap_route_command.go index 2f1c2e4157d..d6bc80da0a2 100644 --- a/command/v7/unmap_route_command.go +++ b/command/v7/unmap_route_command.go @@ -38,7 +38,7 @@ func (cmd UnmapRouteCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/unmap_route_command_test.go b/command/v7/unmap_route_command_test.go index 935ff65b41d..03ab812213a 100644 --- a/command/v7/unmap_route_command_test.go +++ b/command/v7/unmap_route_command_test.go @@ -83,7 +83,7 @@ var _ = Describe("unmap-route Command", func() { GUID: spaceGUID, }) - fakeConfig.CurrentUserReturns(configv3.User{Name: userName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: userName}, nil) fakeActor.GetDomainByNameReturns( resources.Domain{Name: "some-domain.com", GUID: "domain-guid"}, @@ -138,7 +138,7 @@ var _ = Describe("unmap-route Command", func() { BeforeEach(func() { expectedErr = errors.New("some current user error") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("return an error", func() { diff --git a/command/v7/unset_env_command.go b/command/v7/unset_env_command.go index e1c4e1224ac..47243449dda 100644 --- a/command/v7/unset_env_command.go +++ b/command/v7/unset_env_command.go @@ -20,7 +20,7 @@ func (cmd UnsetEnvCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/unset_env_command_test.go b/command/v7/unset_env_command_test.go index d1981cb8ee0..2e1175dc50b 100644 --- a/command/v7/unset_env_command_test.go +++ b/command/v7/unset_env_command_test.go @@ -77,7 +77,7 @@ var _ = Describe("unset-env Command", func() { When("getting the current user returns an error", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("some-error")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("some-error")) }) It("returns the error", func() { @@ -87,7 +87,7 @@ var _ = Describe("unset-env Command", func() { When("getting the current user succeeds", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "banana"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "banana"}, nil) }) When("unsetting the environment variable succeeds", func() { diff --git a/command/v7/unset_org_role_command.go b/command/v7/unset_org_role_command.go index c77cf45706b..c7798f0d174 100644 --- a/command/v7/unset_org_role_command.go +++ b/command/v7/unset_org_role_command.go @@ -26,7 +26,7 @@ func (cmd *UnsetOrgRoleCommand) Execute(args []string) error { return err } - currentUser, err := cmd.Config.CurrentUser() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/unset_org_role_command_test.go b/command/v7/unset_org_role_command_test.go index dbf7edd48df..7e4695e4ec9 100644 --- a/command/v7/unset_org_role_command_test.go +++ b/command/v7/unset_org_role_command_test.go @@ -55,7 +55,7 @@ var _ = Describe("unset-org-role Command", func() { }) BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "current-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "current-user"}, nil) fakeActor.GetOrganizationByNameReturns( resources.Organization{ diff --git a/command/v7/unset_space_quota_command.go b/command/v7/unset_space_quota_command.go index c5ac052ad6a..39d4f8bd6ef 100644 --- a/command/v7/unset_space_quota_command.go +++ b/command/v7/unset_space_quota_command.go @@ -18,7 +18,7 @@ func (cmd *UnsetSpaceQuotaCommand) Execute(args []string) error { return err } - currentUser, err := cmd.Config.CurrentUserName() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } @@ -28,7 +28,7 @@ func (cmd *UnsetSpaceQuotaCommand) Execute(args []string) error { cmd.UI.DisplayTextWithFlavor("Unassigning space quota {{.QuotaName}} from space {{.SpaceName}} as {{.UserName}}...", map[string]interface{}{ "QuotaName": cmd.RequiredArgs.SpaceQuota, "SpaceName": cmd.RequiredArgs.Space, - "UserName": currentUser, + "UserName": currentUser.Name, }) warnings, err := cmd.Actor.UnsetSpaceQuota(cmd.RequiredArgs.SpaceQuota, cmd.RequiredArgs.Space, targetedOrgGUID) diff --git a/command/v7/unset_space_quota_command_test.go b/command/v7/unset_space_quota_command_test.go index 0aa1cf93dca..3a93e9dd666 100644 --- a/command/v7/unset_space_quota_command_test.go +++ b/command/v7/unset_space_quota_command_test.go @@ -73,7 +73,7 @@ var _ = Describe("unset-space-quota Command", func() { When("getting the current user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserNameReturns("", errors.New("current-user-error")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("current-user-error")) }) It("returns the error", func() { @@ -96,8 +96,7 @@ var _ = Describe("unset-space-quota Command", func() { GUID: "some-org-guid", }) - fakeConfig.CurrentUserNameReturns(currentUser, nil) - + fakeActor.GetCurrentUserReturns(configv3.User{Name: currentUser}, nil) }) It("unsets the quota to the organization", func() { @@ -136,8 +135,7 @@ var _ = Describe("unset-space-quota Command", func() { GUID: "some-org-guid", }) - fakeConfig.CurrentUserNameReturns(currentUser, nil) - + fakeActor.GetCurrentUserReturns(configv3.User{Name: currentUser}, nil) }) It("unsets the quota to the organization", func() { diff --git a/command/v7/unset_space_role_command.go b/command/v7/unset_space_role_command.go index 0bfc040bf58..56abfc332fb 100644 --- a/command/v7/unset_space_role_command.go +++ b/command/v7/unset_space_role_command.go @@ -26,7 +26,7 @@ func (cmd *UnsetSpaceRoleCommand) Execute(args []string) error { return err } - currentUser, err := cmd.Config.CurrentUser() + currentUser, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/unset_space_role_command_test.go b/command/v7/unset_space_role_command_test.go index ef0105e3885..e5c9e760943 100644 --- a/command/v7/unset_space_role_command_test.go +++ b/command/v7/unset_space_role_command_test.go @@ -55,7 +55,7 @@ var _ = Describe("unset-space-role Command", func() { }) BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "current-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "current-user"}, nil) fakeActor.GetOrganizationByNameReturns( resources.Organization{ diff --git a/command/v7/unshare_private_domain_command.go b/command/v7/unshare_private_domain_command.go index 69cfccb1f89..d2fe3878251 100644 --- a/command/v7/unshare_private_domain_command.go +++ b/command/v7/unshare_private_domain_command.go @@ -18,7 +18,7 @@ func (cmd UnsharePrivateDomainCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/unshare_private_domain_command_test.go b/command/v7/unshare_private_domain_command_test.go index b83d95bdc88..12e92e52b17 100644 --- a/command/v7/unshare_private_domain_command_test.go +++ b/command/v7/unshare_private_domain_command_test.go @@ -78,7 +78,7 @@ var _ = Describe("unshare-private-domain command", func() { When("getting the current user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("current-user-error")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("current-user-error")) }) It("returns an error", func() { @@ -93,7 +93,7 @@ var _ = Describe("unshare-private-domain command", func() { When("the environment is setup correctly", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{Name: "the-user"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "the-user"}, nil) }) When("the user says yes", func() { diff --git a/command/v7/unshare_service_command.go b/command/v7/unshare_service_command.go index 714da9daa81..73d1d213cbf 100644 --- a/command/v7/unshare_service_command.go +++ b/command/v7/unshare_service_command.go @@ -66,7 +66,7 @@ func (cmd UnshareServiceCommand) Execute(args []string) error { } func (cmd UnshareServiceCommand) displayIntro() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/unshare_service_command_test.go b/command/v7/unshare_service_command_test.go index 9243a46fd4e..e5ae7caa0fc 100644 --- a/command/v7/unshare_service_command_test.go +++ b/command/v7/unshare_service_command_test.go @@ -114,7 +114,7 @@ var _ = Describe("unshare-service command", func() { fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: expectedTargetedOrgName}) fakeConfig.TargetedSpaceReturns(configv3.Space{Name: expectedSpaceName, GUID: expectedTargetedSpaceGuid}) - fakeConfig.CurrentUserReturns(configv3.User{Name: expectedUser}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: expectedUser}, nil) cmd = UnshareServiceCommand{ BaseCommand: BaseCommand{ @@ -156,7 +156,7 @@ var _ = Describe("unshare-service command", func() { fakeSharedActor.CheckTargetReturns(nil) fakeConfig.TargetedSpaceReturns(configv3.Space{GUID: expectedTargetedSpaceGuid}) fakeConfig.TargetedOrganizationReturns(configv3.Organization{GUID: expectedTargetedOrgGuid, Name: expectedTargetedOrgName}) - fakeConfig.CurrentUserReturns(configv3.User{Name: expectedUser}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: expectedUser}, nil) }) It("prompts the user", func() { @@ -220,7 +220,7 @@ var _ = Describe("unshare-service command", func() { When("getting the username fails", func() { BeforeEach(func() { input.Write([]byte("y\n")) - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("boom")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("boom")) }) It("returns the error", func() { diff --git a/command/v7/update_buildpack_command.go b/command/v7/update_buildpack_command.go index 5a59f7def14..b0e40dee66b 100644 --- a/command/v7/update_buildpack_command.go +++ b/command/v7/update_buildpack_command.go @@ -91,7 +91,7 @@ func (cmd UpdateBuildpackCommand) validateSetup() (configv3.User, error) { return user, err } - return cmd.Config.CurrentUser() + return cmd.Actor.GetCurrentUser() } func (cmd UpdateBuildpackCommand) prepareBuildpackBits() (string, string, error) { diff --git a/command/v7/update_buildpack_command_test.go b/command/v7/update_buildpack_command_test.go index da56d6524f8..05de1f2e8a9 100644 --- a/command/v7/update_buildpack_command_test.go +++ b/command/v7/update_buildpack_command_test.go @@ -147,7 +147,7 @@ var _ = Describe("UpdateBuildpackCommand", func() { When("getting the current user fails", func() { BeforeEach(func() { expectedErr = errors.New("some-error that happened") - fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) }) It("returns the error", func() { @@ -160,7 +160,7 @@ var _ = Describe("UpdateBuildpackCommand", func() { BeforeEach(func() { userName = "some-user" - fakeConfig.CurrentUserReturns(configv3.User{Name: userName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: userName}, nil) }) When("preparing buildpack bits causes an error", func() { diff --git a/command/v7/update_org_quota_command.go b/command/v7/update_org_quota_command.go index cc188b329a4..04a93c6a7b8 100644 --- a/command/v7/update_org_quota_command.go +++ b/command/v7/update_org_quota_command.go @@ -35,7 +35,7 @@ func (cmd UpdateOrgQuotaCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/update_org_quota_command_test.go b/command/v7/update_org_quota_command_test.go index cd903e1aa03..4dd534d5dc2 100644 --- a/command/v7/update_org_quota_command_test.go +++ b/command/v7/update_org_quota_command_test.go @@ -49,7 +49,7 @@ var _ = Describe("UpdateOrgQuotaCommand", func() { } currentUserName = "bob" - fakeConfig.CurrentUserReturns(configv3.User{Name: currentUserName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: currentUserName}, nil) }) JustBeforeEach(func() { diff --git a/command/v7/update_security_group_command.go b/command/v7/update_security_group_command.go index 8cd8a1c5fac..6fdbbd3f6e2 100644 --- a/command/v7/update_security_group_command.go +++ b/command/v7/update_security_group_command.go @@ -21,7 +21,7 @@ func (cmd UpdateSecurityGroupCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/update_security_group_command_test.go b/command/v7/update_security_group_command_test.go index c15652a450d..cc4b82fdbae 100644 --- a/command/v7/update_security_group_command_test.go +++ b/command/v7/update_security_group_command_test.go @@ -53,7 +53,7 @@ var _ = Describe("update-security-group Command", func() { } fakeConfig.HasTargetedOrganizationReturns(false) fakeConfig.HasTargetedSpaceReturns(false) - fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: "steve"}, nil) }) JustBeforeEach(func() { diff --git a/command/v7/update_service_broker_command.go b/command/v7/update_service_broker_command.go index ad39ad1393c..8380755d656 100644 --- a/command/v7/update_service_broker_command.go +++ b/command/v7/update_service_broker_command.go @@ -24,7 +24,7 @@ func (cmd UpdateServiceBrokerCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/update_service_broker_command_test.go b/command/v7/update_service_broker_command_test.go index 8a95d70d17c..d3a2b658bc4 100644 --- a/command/v7/update_service_broker_command_test.go +++ b/command/v7/update_service_broker_command_test.go @@ -59,7 +59,7 @@ var _ = Describe("update-service-broker command", func() { nil, ) - fakeConfig.CurrentUserReturns(configv3.User{Name: "user"}, nil) + fakeUpdateServiceBrokerActor.GetCurrentUserReturns(configv3.User{Name: "user"}, nil) }) It("succeeds", func() { @@ -113,7 +113,7 @@ var _ = Describe("update-service-broker command", func() { When("it fails to get the current user", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("no user found")) + fakeUpdateServiceBrokerActor.GetCurrentUserReturns(configv3.User{}, errors.New("no user found")) }) It("returns the error and displays all warnings", func() { diff --git a/command/v7/update_service_command.go b/command/v7/update_service_command.go index 6ce5f3157d6..289cec1ed8c 100644 --- a/command/v7/update_service_command.go +++ b/command/v7/update_service_command.go @@ -115,7 +115,7 @@ CF_NAME update-service mydb -t "list, of, tags" } func (cmd UpdateServiceCommand) displayIntro() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/update_service_command_test.go b/command/v7/update_service_command_test.go index ffa549d2f2c..5e9a55b1f49 100644 --- a/command/v7/update_service_command_test.go +++ b/command/v7/update_service_command_test.go @@ -60,7 +60,7 @@ var _ = Describe("update-service command", func() { Name: spaceName, GUID: spaceGUID, }) - fakeConfig.CurrentUserReturns(configv3.User{Name: username}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: username}, nil) fakeStream := make(chan v7action.PollJobEvent) close(fakeStream) @@ -266,7 +266,7 @@ var _ = Describe("update-service command", func() { When("getting the user fails", func() { BeforeEach(func() { - fakeConfig.CurrentUserReturns(configv3.User{}, errors.New("bang")) + fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("bang")) }) It("returns the error", func() { diff --git a/command/v7/update_space_quota_command.go b/command/v7/update_space_quota_command.go index d5e30b1fc5a..c2905ecae64 100644 --- a/command/v7/update_space_quota_command.go +++ b/command/v7/update_space_quota_command.go @@ -35,7 +35,7 @@ func (cmd UpdateSpaceQuotaCommand) Execute(args []string) error { return err } - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/update_space_quota_command_test.go b/command/v7/update_space_quota_command_test.go index 37f1d10cffe..2caf0945a62 100644 --- a/command/v7/update_space_quota_command_test.go +++ b/command/v7/update_space_quota_command_test.go @@ -50,7 +50,7 @@ var _ = Describe("UpdateSpaceQuotaCommand", func() { } currentUserName = "bob" - fakeConfig.CurrentUserReturns(configv3.User{Name: currentUserName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: currentUserName}, nil) fakeConfig.TargetedOrganizationReturns(configv3.Organization{GUID: "targeted-org-guid"}) fakeConfig.TargetedOrganizationNameReturns(orgName) }) diff --git a/command/v7/update_user_provided_service_command.go b/command/v7/update_user_provided_service_command.go index fde7c3ae375..71b9eb1a6e4 100644 --- a/command/v7/update_user_provided_service_command.go +++ b/command/v7/update_user_provided_service_command.go @@ -63,7 +63,7 @@ func (cmd *UpdateUserProvidedServiceCommand) Execute(args []string) error { } func (cmd UpdateUserProvidedServiceCommand) displayMessage() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/update_user_provided_service_command_test.go b/command/v7/update_user_provided_service_command_test.go index f590ca95b98..ac55f322aa7 100644 --- a/command/v7/update_user_provided_service_command_test.go +++ b/command/v7/update_user_provided_service_command_test.go @@ -97,7 +97,7 @@ var _ = Describe("update-user-provided-service Command", func() { Name: fakeOrgName, }) - fakeConfig.CurrentUserReturns(configv3.User{Name: fakeUserName}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: fakeUserName}, nil) setPositionalFlags(&cmd, fakeServiceInstanceName) diff --git a/command/v7/upgrade_service_command.go b/command/v7/upgrade_service_command.go index 9b67cc851cc..81bd39a065a 100644 --- a/command/v7/upgrade_service_command.go +++ b/command/v7/upgrade_service_command.go @@ -65,7 +65,7 @@ func (cmd UpgradeServiceCommand) Usage() string { } func (cmd UpgradeServiceCommand) displayEvent() error { - user, err := cmd.Config.CurrentUser() + user, err := cmd.Actor.GetCurrentUser() if err != nil { return err } diff --git a/command/v7/upgrade_service_command_test.go b/command/v7/upgrade_service_command_test.go index dfb6c34061a..bc8aa3f54fa 100644 --- a/command/v7/upgrade_service_command_test.go +++ b/command/v7/upgrade_service_command_test.go @@ -58,7 +58,7 @@ var _ = Describe("upgrade-service command", func() { Name: spaceName, GUID: spaceGUID, }) - fakeConfig.CurrentUserReturns(configv3.User{Name: username}, nil) + fakeActor.GetCurrentUserReturns(configv3.User{Name: username}, nil) }) JustBeforeEach(func() { diff --git a/command/v7/v7fakes/fake_actor.go b/command/v7/v7fakes/fake_actor.go index 96679e882bc..8065bc84341 100644 --- a/command/v7/v7fakes/fake_actor.go +++ b/command/v7/v7fakes/fake_actor.go @@ -17,6 +17,7 @@ import ( v7 "code.cloudfoundry.org/cli/command/v7" "code.cloudfoundry.org/cli/resources" "code.cloudfoundry.org/cli/types" + "code.cloudfoundry.org/cli/util/configv3" "github.com/SermoDigital/jose/jwt" ) @@ -1210,6 +1211,18 @@ type FakeActor struct { result2 v7action.Warnings result3 error } + GetCurrentUserStub func() (configv3.User, error) + getCurrentUserMutex sync.RWMutex + getCurrentUserArgsForCall []struct { + } + getCurrentUserReturns struct { + result1 configv3.User + result2 error + } + getCurrentUserReturnsOnCall map[int]struct { + result1 configv3.User + result2 error + } GetDefaultDomainStub func(string) (resources.Domain, v7action.Warnings, error) getDefaultDomainMutex sync.RWMutex getDefaultDomainArgsForCall []struct { @@ -8714,6 +8727,61 @@ func (fake *FakeActor) GetBuildpacksReturnsOnCall(i int, result1 []resources.Bui }{result1, result2, result3} } +func (fake *FakeActor) GetCurrentUser() (configv3.User, error) { + fake.getCurrentUserMutex.Lock() + ret, specificReturn := fake.getCurrentUserReturnsOnCall[len(fake.getCurrentUserArgsForCall)] + fake.getCurrentUserArgsForCall = append(fake.getCurrentUserArgsForCall, struct { + }{}) + fake.recordInvocation("GetCurrentUser", []interface{}{}) + fake.getCurrentUserMutex.Unlock() + if fake.GetCurrentUserStub != nil { + return fake.GetCurrentUserStub() + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getCurrentUserReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeActor) GetCurrentUserCallCount() int { + fake.getCurrentUserMutex.RLock() + defer fake.getCurrentUserMutex.RUnlock() + return len(fake.getCurrentUserArgsForCall) +} + +func (fake *FakeActor) GetCurrentUserCalls(stub func() (configv3.User, error)) { + fake.getCurrentUserMutex.Lock() + defer fake.getCurrentUserMutex.Unlock() + fake.GetCurrentUserStub = stub +} + +func (fake *FakeActor) GetCurrentUserReturns(result1 configv3.User, result2 error) { + fake.getCurrentUserMutex.Lock() + defer fake.getCurrentUserMutex.Unlock() + fake.GetCurrentUserStub = nil + fake.getCurrentUserReturns = struct { + result1 configv3.User + result2 error + }{result1, result2} +} + +func (fake *FakeActor) GetCurrentUserReturnsOnCall(i int, result1 configv3.User, result2 error) { + fake.getCurrentUserMutex.Lock() + defer fake.getCurrentUserMutex.Unlock() + fake.GetCurrentUserStub = nil + if fake.getCurrentUserReturnsOnCall == nil { + fake.getCurrentUserReturnsOnCall = make(map[int]struct { + result1 configv3.User + result2 error + }) + } + fake.getCurrentUserReturnsOnCall[i] = struct { + result1 configv3.User + result2 error + }{result1, result2} +} + func (fake *FakeActor) GetDefaultDomain(arg1 string) (resources.Domain, v7action.Warnings, error) { fake.getDefaultDomainMutex.Lock() ret, specificReturn := fake.getDefaultDomainReturnsOnCall[len(fake.getDefaultDomainArgsForCall)] @@ -18934,6 +19002,8 @@ func (fake *FakeActor) Invocations() map[string][][]interface{} { defer fake.getBuildpackLabelsMutex.RUnlock() fake.getBuildpacksMutex.RLock() defer fake.getBuildpacksMutex.RUnlock() + fake.getCurrentUserMutex.RLock() + defer fake.getCurrentUserMutex.RUnlock() fake.getDefaultDomainMutex.RLock() defer fake.getDefaultDomainMutex.RUnlock() fake.getDetailedAppSummaryMutex.RLock() diff --git a/command/v7/v7fakes/fake_set_label_actor.go b/command/v7/v7fakes/fake_set_label_actor.go index 676d0f4245d..8eb74fcb505 100644 --- a/command/v7/v7fakes/fake_set_label_actor.go +++ b/command/v7/v7fakes/fake_set_label_actor.go @@ -7,9 +7,22 @@ import ( "code.cloudfoundry.org/cli/actor/v7action" v7 "code.cloudfoundry.org/cli/command/v7" "code.cloudfoundry.org/cli/types" + "code.cloudfoundry.org/cli/util/configv3" ) type FakeSetLabelActor struct { + GetCurrentUserStub func() (configv3.User, error) + getCurrentUserMutex sync.RWMutex + getCurrentUserArgsForCall []struct { + } + getCurrentUserReturns struct { + result1 configv3.User + result2 error + } + getCurrentUserReturnsOnCall map[int]struct { + result1 configv3.User + result2 error + } UpdateApplicationLabelsByApplicationNameStub func(string, string, map[string]types.NullString) (v7action.Warnings, error) updateApplicationLabelsByApplicationNameMutex sync.RWMutex updateApplicationLabelsByApplicationNameArgsForCall []struct { @@ -176,6 +189,61 @@ type FakeSetLabelActor struct { invocationsMutex sync.RWMutex } +func (fake *FakeSetLabelActor) GetCurrentUser() (configv3.User, error) { + fake.getCurrentUserMutex.Lock() + ret, specificReturn := fake.getCurrentUserReturnsOnCall[len(fake.getCurrentUserArgsForCall)] + fake.getCurrentUserArgsForCall = append(fake.getCurrentUserArgsForCall, struct { + }{}) + fake.recordInvocation("GetCurrentUser", []interface{}{}) + fake.getCurrentUserMutex.Unlock() + if fake.GetCurrentUserStub != nil { + return fake.GetCurrentUserStub() + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getCurrentUserReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeSetLabelActor) GetCurrentUserCallCount() int { + fake.getCurrentUserMutex.RLock() + defer fake.getCurrentUserMutex.RUnlock() + return len(fake.getCurrentUserArgsForCall) +} + +func (fake *FakeSetLabelActor) GetCurrentUserCalls(stub func() (configv3.User, error)) { + fake.getCurrentUserMutex.Lock() + defer fake.getCurrentUserMutex.Unlock() + fake.GetCurrentUserStub = stub +} + +func (fake *FakeSetLabelActor) GetCurrentUserReturns(result1 configv3.User, result2 error) { + fake.getCurrentUserMutex.Lock() + defer fake.getCurrentUserMutex.Unlock() + fake.GetCurrentUserStub = nil + fake.getCurrentUserReturns = struct { + result1 configv3.User + result2 error + }{result1, result2} +} + +func (fake *FakeSetLabelActor) GetCurrentUserReturnsOnCall(i int, result1 configv3.User, result2 error) { + fake.getCurrentUserMutex.Lock() + defer fake.getCurrentUserMutex.Unlock() + fake.GetCurrentUserStub = nil + if fake.getCurrentUserReturnsOnCall == nil { + fake.getCurrentUserReturnsOnCall = make(map[int]struct { + result1 configv3.User + result2 error + }) + } + fake.getCurrentUserReturnsOnCall[i] = struct { + result1 configv3.User + result2 error + }{result1, result2} +} + func (fake *FakeSetLabelActor) UpdateApplicationLabelsByApplicationName(arg1 string, arg2 string, arg3 map[string]types.NullString) (v7action.Warnings, error) { fake.updateApplicationLabelsByApplicationNameMutex.Lock() ret, specificReturn := fake.updateApplicationLabelsByApplicationNameReturnsOnCall[len(fake.updateApplicationLabelsByApplicationNameArgsForCall)] @@ -891,6 +959,8 @@ func (fake *FakeSetLabelActor) UpdateStackLabelsByStackNameReturnsOnCall(i int, func (fake *FakeSetLabelActor) Invocations() map[string][][]interface{} { fake.invocationsMutex.RLock() defer fake.invocationsMutex.RUnlock() + fake.getCurrentUserMutex.RLock() + defer fake.getCurrentUserMutex.RUnlock() fake.updateApplicationLabelsByApplicationNameMutex.RLock() defer fake.updateApplicationLabelsByApplicationNameMutex.RUnlock() fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.RLock() diff --git a/go.mod b/go.mod index d67598838c6..4733b4ee0d6 100644 --- a/go.mod +++ b/go.mod @@ -9,8 +9,8 @@ require ( code.cloudfoundry.org/cli/integration/assets/hydrabroker v0.0.0-20201002233634-81722a1144e4 code.cloudfoundry.org/clock v1.0.0 code.cloudfoundry.org/diego-ssh v0.0.0-20170109142818-18cdb3586e7f - code.cloudfoundry.org/go-log-cache v1.0.1-0.20200316170138-f466e0302c34 - code.cloudfoundry.org/go-loggregator v7.4.0+incompatible + code.cloudfoundry.org/go-log-cache v1.0.1-0.20211011162012-ede82a99d3cc + code.cloudfoundry.org/go-loggregator/v8 v8.0.5 code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f code.cloudfoundry.org/jsonry v1.1.3 code.cloudfoundry.org/lager v1.1.1-0.20191008172124-a9afc05ee5be @@ -40,7 +40,7 @@ require ( github.com/moby/moby v1.4.2-0.20171120205147-9de84a78d76e github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d github.com/onsi/ginkgo v1.16.4 - github.com/onsi/gomega v1.10.5 + github.com/onsi/gomega v1.13.0 github.com/opencontainers/go-digest v1.0.0-rc1 // indirect github.com/pkg/errors v0.9.1 github.com/sabhiram/go-gitignore v0.0.0-20171017070213-362f9845770f @@ -50,14 +50,15 @@ require ( github.com/tedsuo/rata v1.0.1-0.20170830210128-07d200713958 github.com/vito/go-interact v0.0.0-20171111012221-fa338ed9e9ec golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 - golang.org/x/net v0.0.0-20210716203947-853a461950ff - golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect - golang.org/x/text v0.3.6 - golang.org/x/tools v0.1.5 // indirect - gopkg.in/cheggaaa/pb.v1 v1.0.27 - gopkg.in/yaml.v2 v2.3.0 + golang.org/x/net v0.0.0-20211013171255-e13a2654a71e + golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect + golang.org/x/text v0.3.7 + golang.org/x/tools v0.1.6-0.20210908190839-cf92b39a962c // indirect + google.golang.org/genproto v0.0.0-20211013025323-ce878158c4d4 // indirect + google.golang.org/grpc v1.41.0 // indirect + gopkg.in/cheggaaa/pb.v1 v1.0.28 + gopkg.in/yaml.v2 v2.4.0 + k8s.io/client-go v0.22.2 ) replace gopkg.in/fsnotify.v1 v1.4.7 => github.com/fsnotify/fsnotify v1.4.7 - -replace github.com/golang/protobuf => github.com/golang/protobuf v1.3.4 diff --git a/go.sum b/go.sum index 4bcafc592e3..6ee6cbe53b0 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,36 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= code.cloudfoundry.org/bytefmt v0.0.0-20170428003108-f4415fafc561 h1:OKYHUwj6pyB9KWBoyy1yPJVWvoYV2N+9QqbvbSw8LjM= code.cloudfoundry.org/bytefmt v0.0.0-20170428003108-f4415fafc561/go.mod h1:wN/zk7mhREp/oviagqUXY3EwuHhWyOvAdsn5Y4CzOrc= code.cloudfoundry.org/cfnetworking-cli-api v0.0.0-20190103195135-4b04f26287a6 h1:Yc9r1p21kEpni9WlG4mwOZw87TB2QlyS9sAEebZ3+ak= @@ -11,29 +43,53 @@ code.cloudfoundry.org/clock v1.0.0 h1:kFXWQM4bxYvdBw2X8BbBeXwQNgfoWv1vqAk2ZZyBN2 code.cloudfoundry.org/clock v1.0.0/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8= code.cloudfoundry.org/diego-ssh v0.0.0-20170109142818-18cdb3586e7f h1:xDSTgaS6b/AkaBqvyEYfu6i1Z+y8JSCHAd/e1HGqyF4= code.cloudfoundry.org/diego-ssh v0.0.0-20170109142818-18cdb3586e7f/go.mod h1:L2/glHnSK+wKnsG8oZZqdV2sgYY9NDo/I1aDJGhcWaM= +code.cloudfoundry.org/go-diodes v0.0.0-20180905200951-72629b5276e3/go.mod h1:Jzi+ccHgo/V/PLQUaQ6hnZcC1c4BS790gx21LRRui4g= code.cloudfoundry.org/go-envstruct v1.5.0/go.mod h1:E2S/gzRZpZ51PZnIv7Bo7QvcgH18yio19upkrRk0xLU= -code.cloudfoundry.org/go-log-cache v1.0.1-0.20200316170138-f466e0302c34 h1:cSOAscWrWx7uix5SjqePlqDad/n8f2A/bugsSttxVx4= -code.cloudfoundry.org/go-log-cache v1.0.1-0.20200316170138-f466e0302c34/go.mod h1:0+5CSLZehiHLkrWCmwPt7mA/RlAa71idWz4SG4wfhOE= -code.cloudfoundry.org/go-loggregator v7.4.0+incompatible h1:KqZYloMQWM5Zg/BQKunOIA4OODh7djZbk48qqbowNFI= -code.cloudfoundry.org/go-loggregator v7.4.0+incompatible/go.mod h1:KPBTRqj+y738Nhf1+g4JHFaBU8j7dedirR5ETNHvMXU= +code.cloudfoundry.org/go-log-cache v1.0.1-0.20211011162012-ede82a99d3cc h1:8gj5Z08i9ZvoIGi1A/E2CEQTbvJjogYQgBQUI2/DyNE= +code.cloudfoundry.org/go-log-cache v1.0.1-0.20211011162012-ede82a99d3cc/go.mod h1:8thG6lrstlbeI44hc7QgSnX8eau68+mNt9Pp33/TEcg= +code.cloudfoundry.org/go-loggregator/v8 v8.0.2-0.20200722201844-b5130958b65d/go.mod h1:Or3cWTXwK6d3caPRBTUJv/suT+47jOltB7hYC/3ECCo= +code.cloudfoundry.org/go-loggregator/v8 v8.0.5 h1:p1rrGxTwUqLjlUVtbjTAvKOSGNmPuBja8LeQOQgRrBc= +code.cloudfoundry.org/go-loggregator/v8 v8.0.5/go.mod h1:mLlJ1ZyG6gVvBEtYypvbztRvFeCtBsTxE9tt+85tS6Y= code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f h1:UrKzEwTgeiff9vxdrfdqxibzpWjxLnuXDI5m6z3GJAk= code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f/go.mod h1:sk5LnIjB/nIEU7yP5sDQExVm62wu0pBh3yrElngUisI= code.cloudfoundry.org/jsonry v1.1.3 h1:pt7JvBaoZEObO9lppoAMjpscsE2uv7OKX9JiB3oNYxE= code.cloudfoundry.org/jsonry v1.1.3/go.mod h1:IYd9/qJOvdVQk/SEkw3zPKpJp4GNAN+LYjU9eD3pspo= code.cloudfoundry.org/lager v1.1.1-0.20191008172124-a9afc05ee5be h1:rnGRgbKlOPKbI9N/PscJ78Ug5Iw+o1kE7aDW01V+0FM= code.cloudfoundry.org/lager v1.1.1-0.20191008172124-a9afc05ee5be/go.mod h1:O2sS7gKP3HM2iemG+EnwvyNQK7pTSC6Foi4QiMp9sSk= -code.cloudfoundry.org/rfc5424 v0.0.0-20180905210152-236a6d29298a h1:8rqv2w8xEceNwckcF5ONeRt0qBHlh5bnNfFnYTrZbxs= code.cloudfoundry.org/rfc5424 v0.0.0-20180905210152-236a6d29298a/go.mod h1:tkZo8GtzBjySJ7USvxm4E36lNQw1D3xM6oKHGqdaAJ4= +code.cloudfoundry.org/tlsconfig v0.0.0-20200131000646-bbe0f8da39b3/go.mod h1:eTbFJpyXRGuFVyg5+oaj9B2eIbIc+0/kZjH8ftbtdew= code.cloudfoundry.org/tlsconfig v0.0.0-20210615191307-5d92ef3894a7 h1:5N6M1WbWH3bknkX80Q/s7eEo5odqjixLAW79Zrrbqu0= code.cloudfoundry.org/tlsconfig v0.0.0-20210615191307-5d92ef3894a7/go.mod h1:CKI5CV+3MlfcohVSuU3FxXubFyC52lYJGMLnZ2ltvks= code.cloudfoundry.org/ykk v0.0.0-20170424192843-e4df4ce2fd4d h1:M+zXqtXJqcsmpL76aU0tdl1ho23eYa4axYoM4gD62UA= code.cloudfoundry.org/ykk v0.0.0-20170424192843-e4df4ce2fd4d/go.mod h1:YUJiVOr5xl0N/RjMxM1tHmgSpBbi5UM+KoVR5AoejO0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.18 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/SermoDigital/jose v0.9.2-0.20161205224733-f6df55f235c2 h1:koK7z0nSsRiRiBWwa+E714Puh+DO+ZRdIyAXiXzL+lg= github.com/SermoDigital/jose v0.9.2-0.20161205224733-f6df55f235c2/go.mod h1:ARgCUhI1MHQH+ONky/PAtmVHQrP5JlGY0F3poXOp/fA= -github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apoydence/eachers v0.0.0-20181020210610-23942921fe77/go.mod h1:bXvGk6IkT1Agy7qzJ+DjIw/SJ1AaB3AvAuMDVV+Vkoo= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bmatcuk/doublestar v1.3.1 h1:rT8rxDPsavp9G+4ZULzqhhUSaI/OPsTZNG88Z3i0xvY= @@ -42,16 +98,30 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dR github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40 h1:y4B3+GPxKlrigF1ha5FFErxK+sr6sWxQovRMzwMhejo= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charlievieth/fs v0.0.0-20170613215519-7dc373669fa1 h1:vTlpHKxJqykyKdW9bkrDJNWeKNuSIAJ0TP/K4lRsz/Q= github.com/charlievieth/fs v0.0.0-20170613215519-7dc373669fa1/go.mod h1:sAoA1zHCH4FJPE2gne5iBiiVG66U7Nyp6JqlOo+FEyg= +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= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudfoundry/bosh-cli v5.5.1+incompatible h1:a4SP5/+ZlnfrMefIhklrw7UkbujwgXPIR0/nfCigI6I= github.com/cloudfoundry/bosh-cli v5.5.1+incompatible/go.mod h1:rzIB+e1sn7wQL/TJ54bl/FemPKRhXby5BIMS3tLuWFM= github.com/cloudfoundry/bosh-utils v0.0.0-20180315210917-c6a922e299b8 h1:x6vZOZ7rlvGro4GKDg0DaQz2za8Q6GjhVoB7vH6BZ2I= github.com/cloudfoundry/bosh-utils v0.0.0-20180315210917-c6a922e299b8/go.mod h1:JCrKwetZGjxbfq1U139TZuXDBfdGLtjOEAfxMWKV/QM= +github.com/cloudfoundry/dropsonde v1.0.0/go.mod h1:6zwvrWK5TpxBVYi1cdkE5WDsIO8E0n7qAJg3wR9B67c= +github.com/cloudfoundry/gosteno v0.0.0-20150423193413-0c8581caea35/go.mod h1:3YBPUR85RIrvaUTdA1dL38YSp6s3OHu1xrWLkGt2Mog= +github.com/cloudfoundry/loggregatorlib v0.0.0-20170823162133-36eddf15ef12/go.mod h1:ucj7+svyACshmxV3Zze2NAcEcdbBf9scZYR+QKCX9/w= +github.com/cloudfoundry/sonde-go v0.0.0-20171206171820-b33733203bb4/go.mod h1:GS0pCHd7onIsewbw8Ue9qa9pZPv2V88cUZDttK6KzgI= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= github.com/cppforlife/go-patch v0.1.0 h1:I0fT+gFTSW4xWwvaTaUUVjr9xxjNXJ4naGc01BeQjwY= github.com/cppforlife/go-patch v0.1.0/go.mod h1:67a7aIi94FHDZdoeGSJRRFDp66l9MhaAG1yGxpUoFD8= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyphar/filepath-securejoin v0.2.1 h1:5DPkzz/0MwUpvR4fxASKzgApeq2OMFY5FfYtrX28Coo= github.com/cyphar/filepath-securejoin v0.2.1/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -61,57 +131,156 @@ github.com/docker/distribution v2.6.0-rc.1.0.20171109224904-e5b5e44386f7+incompa github.com/docker/distribution v2.6.0-rc.1.0.20171109224904-e5b5e44386f7+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20171120205147-9de84a78d76e h1:M+/1NNHE/mg+RUox/04+rZoahJVklPfs6xZFECVnxso= github.com/docker/docker v1.4.2-0.20171120205147-9de84a78d76e/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/drewolson/testflight v1.0.0/go.mod h1:t9oKuuEohRGLb80SWX+uxJHuhX98B7HnojqtW+Ryq30= +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/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.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.5.1-0.20170926111411-5df930a27be2 h1:lSx4zNYRd54K1yU6E/Uak9R4GqTMt7L44QU8aT1W3Go= github.com/fatih/color v1.5.1-0.20170926111411-5df930a27be2/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/grpc-ecosystem/grpc-gateway v1.14.0 h1:CI8J2kQ4VC2vS3lhVQa+5lMpwCyqyNCAWAPHGMGszQw= -github.com/grpc-ecosystem/grpc-gateway v1.14.0/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.6.0 h1:rgxjzoDmDXw5q8HONgyHhBas4to0/XWRo/gPpJhsUNQ= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.6.0/go.mod h1:qrJPVzv9YlhsrxJc3P/Q85nr0w1lIRikTl4JlhdDH5w= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/jessevdk/go-flags v0.0.0-20170926144705-f88afde2fa19/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.1-0.20181221193153-c0795c8afcf4 h1:xKkUL6QBojwguhKKetf1SocCAKqc6W7S/mGm9xEGllo= github.com/jessevdk/go-flags v1.4.1-0.20181221193153-c0795c8afcf4/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/joefitzgerald/rainbow-reporter v0.1.0 h1:AuMG652zjdzI0YCCnXAqATtRBpGXMcAnrajcaTrSeuo= github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.0.0-20160823170715-cfb55aafdaf3/go.mod h1:Bvhd+E3laJ0AVkG0c9rmtZcnhV0HQ3+c3YxxqTvc/gA= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.0.0-20160504234017-7cafcd837844/go.mod h1:sjUstKUATFIcff4qlB53Kml0wQPtJVc/3fWrmuUmcfA= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/loggregator/go-bindata v0.0.0-20190422223605-5f11cfb2d7d9/go.mod h1:PvsJfK9t/8OdGvSanpYlwJ1EPoJ/hwT3c52txAzqooY= github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-colorable v0.1.0 h1:v2XXALHHh6zHfYTJ+cSkwtyffnaOyR1MXaA91mTrb8o= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI= @@ -120,38 +289,57 @@ github.com/mattn/go-runewidth v0.0.5-0.20181218000649-703b5e6b11ae h1:575usOHCDz github.com/mattn/go-runewidth v0.0.5-0.20181218000649-703b5e6b11ae/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2 h1:g+4J5sZg6osfvEfkRZxJ1em0VT95/UOZgi/l7zi1/oE= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/moby/moby v1.4.2-0.20171120205147-9de84a78d76e h1:6+Fs/ljqCOuJ4Ie4VUB/wQ/9oSpk2YvtSR5Clf13puk= github.com/moby/moby v1.4.2-0.20171120205147-9de84a78d76e/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +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/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v0.0.0-20171031171758-652e15c9a27e/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= +github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20171105031654-1eecca0ba8e6/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ= github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= +github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= +github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pivotal-cf/brokerapi/v7 v7.2.0/go.mod h1:5QRQ8vJmav91F+AvY5NA/QoDOq70XgBVxXKUK4N/cNE= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/poy/eachers v0.0.0-20181020210610-23942921fe77/go.mod h1:x1vqpbcMW9T/KRcQ4b48diSiSVtYgvwQ5xzDByEg4WE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -163,14 +351,22 @@ github.com/sclevine/spec v1.2.0 h1:1Jwdf9jSfDl9NVmt8ndHqbTZ7XCCPbh1jI3hkDBHVYA= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/square/certstrap v1.2.0 h1:ecgyABrbFLr8jSbOC6oTBmBek0t/HqtgrMUZCPuyfdw= github.com/square/certstrap v1.2.0/go.mod h1:CUHqV+fxJW0Y5UQFnnbYwQ7bpKXO1AKbic9g73799yw= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tedsuo/ifrit v0.0.0-20191009134036-9a97d0632f00 h1:mujcChM89zOHwgZBBNr5WZ77mBXP1yR+gLThGCYZgAg= github.com/tedsuo/ifrit v0.0.0-20191009134036-9a97d0632f00/go.mod h1:eyZnKCc955uh98WQvzOm0dgAeLnf2O0Rz0LPoC5ze+0= github.com/tedsuo/rata v1.0.1-0.20170830210128-07d200713958 h1:mueRRuRjR35dEOkHdhpoRcruNgBz0ohG659HxxmcAwA= @@ -179,22 +375,58 @@ github.com/unrolled/secure v0.0.0-20180416205222-a1cf62cc2159/go.mod h1:mnPT77IA github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ= github.com/vito/go-interact v0.0.0-20171111012221-fa338ed9e9ec h1:Klu98tQ9Z1t23gvC7p7sCmvxkZxLhBHLNyrUPsWsYFg= github.com/vito/go-interact v0.0.0-20171111012221-fa338ed9e9ec/go.mod h1:wPlfmglZmRWMYv/qJy3P+fK/UnoQB5ISk4txfNd9tDo= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 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-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= @@ -204,26 +436,57 @@ golang.org/x/net v0.0.0-20180418062111-d41e8174641f/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210716203947-853a461950ff h1:j2EK/QoxYNBsXI4R7fQkkRUk8y6wnOBI+6hgPdP/6Ds= -golang.org/x/net v0.0.0-20210716203947-853a461950ff/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211013171255-e13a2654a71e h1:Xj+JO91noE97IN6F/7WZxzC5QE6yENAQPrwIYhW3bsA= +golang.org/x/net v0.0.0-20211013171255-e13a2654a71e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 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= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 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= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180419222023-a2a45943ae67/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -232,12 +495,36 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -245,52 +532,181 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211013075003-97ac67df715c h1:taxlMj0D/1sOAuv/CbSD+MMDof2vbyPTqz5FNYKpXt8= +golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +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 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/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-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/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-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= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +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-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/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-20200609164405-eb789aa7ce50/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-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +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= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210908190839-cf92b39a962c h1:C0nyHiBU2m0cR6hDiUORWqQIt3h37wsp1255QBSSXqY= +golang.org/x/tools v0.1.6-0.20210908190839-cf92b39a962c/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/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-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= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20200304201815-d429ff31ee6c h1:Mm69MraVZ+yh1vw8pQOUW4uJkkSEQbbTr076A94lvqs= -google.golang.org/genproto v0.0.0-20200304201815-d429ff31ee6c/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20211013025323-ce878158c4d4 h1:NBxB1XxiWpGqkPUiJ9PoBXkHV5A9+GohMOA+EmWoPbU= +google.golang.org/genproto v0.0.0-20211013025323-ce878158c4d4/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.27 h1:kJdccidYzt3CaHD1crCFTS1hxyhSi059NhOFUf03YFo= -gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk= +gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20171116090243-287cf08546ab/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= @@ -298,9 +714,41 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.2.0-0.dev/go.mod h1:XtegFAyX/PfluP4921rXU5IkjkqBCDnUq4W8VCIoKvM= +k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= +k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= +k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= +k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= +k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc= +k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= +k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/integration/README.md b/integration/README.md index 021f6641e3b..de326244cb7 100644 --- a/integration/README.md +++ b/integration/README.md @@ -24,7 +24,8 @@ Running `make integration-tests` can be time-consuming, because it includes the - `isolated` suite is for tests that are stand alone and do not affect each other. They are meant to run in their own organization and space, and will not affect system state. This is the most common type of integration tests. - `push` suite is for tests related to the `cf push` command only. - `experimental` suite is for tests that require the cf experimental flag to be set and/or an experimental feature for the CF CLI. -- `plugin` suite is for tests that surround the CF CLI plugin framework. *These tests do not run in parallel.* +- `plugin` suite is for tests that surround the CF CLI plugin framework. _These tests do not run in parallel._ +- `selfcontained` suite is for tests that talk to a fake CF API, hence they do not require a cf deployment ## How to run These tests rely on [ginkgo](https://github.com/onsi/ginkgo) to be installed. diff --git a/integration/helpers/command.go b/integration/helpers/command.go index 377b014db61..f8f7cad7375 100644 --- a/integration/helpers/command.go +++ b/integration/helpers/command.go @@ -39,14 +39,14 @@ func CF(args ...string) *Session { type CFEnv struct { WorkingDirectory string EnvVars map[string]string - stdin io.Reader + Stdin io.Reader } // CustomCF runs a 'cf' command with a custom environment and given arguments. func CustomCF(cfEnv CFEnv, args ...string) *Session { command := exec.Command("cf", args...) - if cfEnv.stdin != nil { - command.Stdin = cfEnv.stdin + if cfEnv.Stdin != nil { + command.Stdin = cfEnv.Stdin } if cfEnv.WorkingDirectory != "" { command.Dir = cfEnv.WorkingDirectory diff --git a/integration/v7/isolated/api_command_test.go b/integration/v7/isolated/api_command_test.go index d312c8035c9..b3339b84679 100644 --- a/integration/v7/isolated/api_command_test.go +++ b/integration/v7/isolated/api_command_test.go @@ -81,7 +81,6 @@ var _ = Describe("api command", func() { Context("--unset is passed", func() { BeforeEach(func() { - userConfig := configv3.Config{ ConfigFile: configv3.JSONConfig{ ConfigVersion: configv3.CurrentConfigVersion, @@ -338,6 +337,7 @@ var _ = Describe("api command", func() { Expect(configFile.TargetedSpace.GUID).To(BeEmpty()) Expect(configFile.TargetedSpace.Name).To(BeEmpty()) Expect(configFile.TargetedSpace.AllowSSH).To(BeFalse()) + Expect(configFile.CFOnK8s).To(Equal(configv3.CFOnK8s{})) }) It("handles API endpoints with trailing slash", func() { diff --git a/integration/v7/isolated/login_command_test.go b/integration/v7/isolated/login_command_test.go index 2aa1c420ace..70004c90b57 100644 --- a/integration/v7/isolated/login_command_test.go +++ b/integration/v7/isolated/login_command_test.go @@ -624,7 +624,7 @@ var _ = Describe("login command", func() { Eventually(session.Err).Should(Say("Service account currently logged in. Use 'cf logout' to log out service account and try again.")) Eventually(session).Should(Exit(1)) - //And I am still logged in + // And I am still logged in targetSession := helpers.CF("target") Eventually(targetSession).Should(Exit(0)) }) diff --git a/integration/v7/selfcontained/api_command_test.go b/integration/v7/selfcontained/api_command_test.go new file mode 100644 index 00000000000..3347cb83b1a --- /dev/null +++ b/integration/v7/selfcontained/api_command_test.go @@ -0,0 +1,99 @@ +package selfcontained_test + +import ( + "net/http" + + "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" + "code.cloudfoundry.org/cli/integration/helpers" + "code.cloudfoundry.org/cli/integration/v7/selfcontained/fake" + "code.cloudfoundry.org/cli/util/configv3" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gexec" +) + +var _ = Describe("cf api", func() { + var apiConfig fake.CFAPIConfig + + BeforeEach(func() { + apiConfig = fake.CFAPIConfig{ + Routes: map[string]fake.Response{ + "GET /": {Code: http.StatusOK, Body: ccv3.Info{}}, + }, + } + apiServer.SetConfiguration(apiConfig) + }) + + JustBeforeEach(func() { + Eventually(helpers.CF("api", apiServer.URL())).Should(gexec.Exit(0)) + }) + + It("disables cf-on-k8s in config", func() { + Expect(loadConfig().CFOnK8s.Enabled).To(BeFalse()) + }) + + When("pointed to cf-on-k8s", func() { + BeforeEach(func() { + apiConfig.Routes["GET /"] = fake.Response{ + Code: http.StatusOK, Body: ccv3.Info{CFOnK8s: true}, + } + apiServer.SetConfiguration(apiConfig) + }) + + It("enables cf-on-k8s in config", func() { + Expect(loadConfig().CFOnK8s.Enabled).To(BeTrue()) + }) + }) + + When("already logged into a cf-on-k8s", func() { + BeforeEach(func() { + helpers.SetConfig(func(config *configv3.Config) { + config.ConfigFile.CFOnK8s.Enabled = true + config.ConfigFile.CFOnK8s.AuthInfo = "something" + }) + }) + + It("disables cf-on-k8s in config and clears the auth-info", func() { + Expect(loadConfig().CFOnK8s).To(Equal(configv3.CFOnK8s{ + Enabled: false, + AuthInfo: "", + })) + }) + + When("pointed to cf-on-k8s", func() { + BeforeEach(func() { + apiConfig.Routes["GET /"] = fake.Response{ + Code: http.StatusOK, Body: ccv3.Info{CFOnK8s: true}, + } + apiServer.SetConfiguration(apiConfig) + }) + + It("clears the auth-info", func() { + Expect(loadConfig().CFOnK8s).To(Equal(configv3.CFOnK8s{ + Enabled: true, + AuthInfo: "", + })) + }) + }) + }) +}) + +var _ = Describe("cf api --unset", func() { + BeforeEach(func() { + helpers.SetConfig(func(config *configv3.Config) { + config.ConfigFile.CFOnK8s.Enabled = true + config.ConfigFile.CFOnK8s.AuthInfo = "something" + }) + }) + + JustBeforeEach(func() { + Eventually(helpers.CF("api", "--unset")).Should(gexec.Exit(0)) + }) + + It("disables cf-on-k8s in config and clears the auth-info", func() { + Expect(loadConfig().CFOnK8s).To(Equal(configv3.CFOnK8s{ + Enabled: false, + AuthInfo: "", + })) + }) +}) diff --git a/integration/v7/selfcontained/create_space_command_test.go b/integration/v7/selfcontained/create_space_command_test.go new file mode 100644 index 00000000000..21c7e65ccb4 --- /dev/null +++ b/integration/v7/selfcontained/create_space_command_test.go @@ -0,0 +1,107 @@ +package selfcontained_test + +import ( + "net/http" + "os" + "path/filepath" + + "code.cloudfoundry.org/cli/integration/helpers" + "code.cloudfoundry.org/cli/integration/v7/selfcontained/fake" + "code.cloudfoundry.org/cli/util/configv3" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + "github.com/onsi/gomega/gexec" + apiv1 "k8s.io/client-go/tools/clientcmd/api/v1" +) + +var _ = Describe("Create Space Command", func() { + Describe("CF-on-k8s", func() { + var ( + kubeConfigPath string + kubeConfig apiv1.Config + session *gexec.Session + apiConfig fake.CFAPIConfig + ) + + BeforeEach(func() { + helpers.SetConfig(func(config *configv3.Config) { + config.ConfigFile.Target = apiServer.URL() + config.ConfigFile.CFOnK8s.Enabled = true + config.ConfigFile.CFOnK8s.AuthInfo = "my-auth" + config.ConfigFile.TargetedOrganization.GUID = "org-guid" + config.ConfigFile.TargetedOrganization.Name = "my-org" + }) + + apiConfig = fake.CFAPIConfig{ + Routes: map[string]fake.Response{ + "POST /v3/spaces": {Code: http.StatusCreated}, + "POST /v3/roles": {Code: http.StatusCreated}, + "GET /whoami": { + Code: http.StatusOK, Body: map[string]interface{}{ + "name": "my-user", + "kind": "User", + }, + }, + }, + } + apiServer.SetConfiguration(apiConfig) + + kubeConfig = apiv1.Config{ + Kind: "Config", + APIVersion: "v1", + AuthInfos: []apiv1.NamedAuthInfo{ + { + Name: "my-auth", + AuthInfo: apiv1.AuthInfo{ + Token: "foo", + }, + }, + }, + Clusters: []apiv1.NamedCluster{ + { + Name: "my-cluster", + Cluster: apiv1.Cluster{ + Server: "https://example.org", + }, + }, + }, + Contexts: []apiv1.NamedContext{ + { + Name: "my-context", + Context: apiv1.Context{ + Cluster: "my-cluster", + AuthInfo: "my-auth", + Namespace: "my-namespace", + }, + }, + }, + CurrentContext: "my-context", + } + + kubeConfigPath := filepath.Join(homeDir, ".kube", "config") + storeKubeConfig(kubeConfig, kubeConfigPath) + + env = helpers.CFEnv{ + EnvVars: map[string]string{ + "KUBECONFIG": kubeConfigPath, + }, + } + }) + + JustBeforeEach(func() { + session = helpers.CustomCF(env, "create-space", "my-space") + }) + + AfterEach(func() { + Expect(os.RemoveAll(kubeConfigPath)).To(Succeed()) + }) + + It("creates a role using the name from the /whoami endpoint", func() { + Eventually(session).Should(gexec.Exit(0)) + + Expect(session).To(gbytes.Say("Assigning role SpaceManager to user my-user in org my-org")) + Expect(session).To(gbytes.Say("Assigning role SpaceDeveloper to user my-user in org my-org")) + }) + }) +}) diff --git a/integration/v7/selfcontained/fake/cf_api.go b/integration/v7/selfcontained/fake/cf_api.go new file mode 100644 index 00000000000..5fecd07102a --- /dev/null +++ b/integration/v7/selfcontained/fake/cf_api.go @@ -0,0 +1,68 @@ +package fake + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + + . "github.com/onsi/gomega" + "github.com/onsi/gomega/ghttp" +) + +type CFAPI struct { + server *ghttp.Server +} + +type CFAPIConfig struct { + Routes map[string]Response +} + +type Response struct { + Code int + Body interface{} +} + +func NewCFAPI() *CFAPI { + server := ghttp.NewServer() + return &CFAPI{ + server: server, + } +} + +func (a *CFAPI) SetConfiguration(config CFAPIConfig) { + a.server.Reset() + + for request, response := range config.Routes { + method, path := parseRequest(request) + responseBytes, err := json.Marshal(response.Body) + Expect(err).NotTo(HaveOccurred()) + + a.server.RouteToHandler(method, path, ghttp.RespondWith(response.Code, responseBytes)) + } +} + +func (a *CFAPI) Close() { + a.server.Close() +} + +func (a *CFAPI) URL() string { + return a.server.URL() +} + +func (a *CFAPI) ReceivedRequests() map[string][]*http.Request { + result := map[string][]*http.Request{} + + for _, req := range a.server.ReceivedRequests() { + key := fmt.Sprintf("%s %s", req.Method, req.URL.Path) + result[key] = append(result[key], req) + } + + return result +} + +func parseRequest(request string) (string, string) { + fields := strings.Split(request, " ") + Expect(fields).To(HaveLen(2)) + return fields[0], fields[1] +} diff --git a/integration/v7/selfcontained/kubernetes_auth_test.go b/integration/v7/selfcontained/kubernetes_auth_test.go new file mode 100644 index 00000000000..113c8e4f175 --- /dev/null +++ b/integration/v7/selfcontained/kubernetes_auth_test.go @@ -0,0 +1,106 @@ +package selfcontained_test + +import ( + "net/http" + "path/filepath" + + "code.cloudfoundry.org/cli/integration/helpers" + "code.cloudfoundry.org/cli/integration/v7/selfcontained/fake" + "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/configv3" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gexec" + apiv1 "k8s.io/client-go/tools/clientcmd/api/v1" +) + +var _ = Describe("auth-provider", func() { + var ( + apiConfig fake.CFAPIConfig + kubeConfig apiv1.Config + ) + + BeforeEach(func() { + apiConfig = fake.CFAPIConfig{ + Routes: map[string]fake.Response{ + "GET /v3/apps": { + Code: http.StatusOK, Body: map[string]interface{}{ + "pagination": map[string]interface{}{}, + "resources": []resources.Application{}, + }, + }, + }, + } + apiServer.SetConfiguration(apiConfig) + helpers.SetConfig(func(config *configv3.Config) { + config.ConfigFile.Target = apiServer.URL() + config.ConfigFile.CFOnK8s.Enabled = true + config.ConfigFile.CFOnK8s.AuthInfo = "one" + config.ConfigFile.TargetedOrganization = configv3.Organization{ + GUID: "my-org", + Name: "My Org", + } + + config.ConfigFile.TargetedSpace = configv3.Space{ + GUID: "my-space", + Name: "My Space", + } + }) + + kubeConfig = apiv1.Config{ + Kind: "Config", + APIVersion: "v1", + AuthInfos: []apiv1.NamedAuthInfo{ + { + Name: "one", AuthInfo: apiv1.AuthInfo{ + AuthProvider: &apiv1.AuthProviderConfig{ + Name: "oidc", + Config: map[string]string{ + "id-token": string(token), + "idp-issuer-url": "-", + "client-id": "-", + }, + }, + }, + }, + }, + Clusters: []apiv1.NamedCluster{ + { + Name: "my-cluster", + Cluster: apiv1.Cluster{ + Server: "https://example.org", + }, + }, + }, + Contexts: []apiv1.NamedContext{ + { + Name: "my-context", + Context: apiv1.Context{ + Cluster: "my-cluster", + AuthInfo: "my-auth-info", + Namespace: "my-namespace", + }, + }, + }, + CurrentContext: "my-context", + } + kubeConfigPath := filepath.Join(homeDir, ".kube", "config") + storeKubeConfig(kubeConfig, kubeConfigPath) + + env = helpers.CFEnv{ + EnvVars: map[string]string{ + "KUBECONFIG": kubeConfigPath, + }, + } + }) + + JustBeforeEach(func() { + Eventually(helpers.CustomCF(env, "apps")).Should(gexec.Exit(0)) + }) + + It("sends the Bearer token in the Authorization header", func() { + reqs := apiServer.ReceivedRequests()["GET /v3/apps"] + Expect(reqs).To(HaveLen(1)) + Expect(reqs[0].Header).To(HaveKeyWithValue("Authorization", ConsistOf("Bearer "+string(token)))) + }) +}) diff --git a/integration/v7/selfcontained/login_command_test.go b/integration/v7/selfcontained/login_command_test.go new file mode 100644 index 00000000000..5e41d783fec --- /dev/null +++ b/integration/v7/selfcontained/login_command_test.go @@ -0,0 +1,165 @@ +package selfcontained_test + +import ( + "fmt" + "net/http" + "os" + "path/filepath" + + "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" + "code.cloudfoundry.org/cli/integration/helpers" + "code.cloudfoundry.org/cli/integration/v7/selfcontained/fake" + "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/configv3" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + "github.com/onsi/gomega/gexec" + apiv1 "k8s.io/client-go/tools/clientcmd/api/v1" +) + +var _ = Describe("LoginCommand", func() { + Describe("CF-on-k8s", func() { + var ( + stdin *gbytes.Buffer + kubeConfigPath string + kubeConfig apiv1.Config + session *gexec.Session + loginArgs []string + apiConfig fake.CFAPIConfig + ) + + BeforeEach(func() { + loginArgs = []string{"login"} + helpers.SetConfig(func(config *configv3.Config) { + config.ConfigFile.Target = apiServer.URL() + config.ConfigFile.CFOnK8s.Enabled = true + }) + + apiConfig = fake.CFAPIConfig{ + Routes: map[string]fake.Response{ + "GET /": {Code: http.StatusOK, Body: ccv3.Info{CFOnK8s: true}}, + "GET /v3/organizations": { + Code: http.StatusOK, Body: map[string]interface{}{ + "pagination": map[string]interface{}{}, + "resources": []resources.Organization{}, + }, + }, + }, + } + apiServer.SetConfiguration(apiConfig) + + kubeConfig = apiv1.Config{ + Kind: "Config", + APIVersion: "v1", + AuthInfos: []apiv1.NamedAuthInfo{ + { + Name: "one", + AuthInfo: apiv1.AuthInfo{ + Token: "foo", + }, + }, + { + Name: "two", + AuthInfo: apiv1.AuthInfo{ + AuthProvider: &apiv1.AuthProviderConfig{ + Name: "oidc", + Config: map[string]string{ + "id-token": string(token), + "idp-issuer-url": "-", + "client-id": "-", + }, + }, + }, + }, + }, + Clusters: []apiv1.NamedCluster{ + { + Name: "my-cluster", + Cluster: apiv1.Cluster{ + Server: "https://example.org", + }, + }, + }, + Contexts: []apiv1.NamedContext{ + { + Name: "my-context", + Context: apiv1.Context{ + Cluster: "my-cluster", + AuthInfo: "my-auth-info", + Namespace: "my-namespace", + }, + }, + }, + CurrentContext: "my-context", + } + + kubeConfigPath := filepath.Join(homeDir, ".kube", "config") + storeKubeConfig(kubeConfig, kubeConfigPath) + + stdin = gbytes.NewBuffer() + _, wErr := fmt.Fprintf(stdin, "%d\n", 2) + Expect(wErr).ToNot(HaveOccurred()) + + env = helpers.CFEnv{ + Stdin: stdin, + EnvVars: map[string]string{ + "KUBECONFIG": kubeConfigPath, + }, + } + }) + + JustBeforeEach(func() { + session = helpers.CustomCF(env, loginArgs...) + }) + + AfterEach(func() { + Expect(os.RemoveAll(kubeConfigPath)).To(Succeed()) + }) + + It("prompts the user to select a user from the kube config file", func() { + Eventually(session).Should(gbytes.Say("1. one")) + Eventually(session).Should(gbytes.Say("2. two")) + Eventually(session).Should(gbytes.Say("Choose your Kubernetes authentication info")) + Eventually(session).Should(gbytes.Say("OK")) + Eventually(session).Should(gexec.Exit(0)) + }) + + It("sets the user into the configuration", func() { + Eventually(session).Should(gexec.Exit(0)) + Expect(loadConfig().CFOnK8s.AuthInfo).To(Equal("two")) + }) + + It("displays the logged in user", func() { + Eventually(session).Should(gbytes.Say("user:(\\s*)two")) + }) + + When("the kubeconfig contains no user information", func() { + BeforeEach(func() { + kubeConfig.AuthInfos = []apiv1.NamedAuthInfo{} + storeKubeConfig(kubeConfig, filepath.Join(homeDir, ".kube", "config")) + }) + + It("displays an error", func() { + Eventually(session.Err).Should(gbytes.Say("Unable to authenticate.")) + Eventually(session).Should(gbytes.Say("FAILED")) + Eventually(session).Should(gexec.Exit(1)) + }) + }) + + When("providing -a flag without having targeted the api before", func() { + BeforeEach(func() { + helpers.SetConfig(func(config *configv3.Config) { + config.ConfigFile.Target = "" + config.ConfigFile.CFOnK8s = configv3.CFOnK8s{} + }) + + loginArgs = append(loginArgs, "-a", apiServer.URL()) + }) + + It("displays the logged in user", func() { + Eventually(session).Should(gbytes.Say("user:(\\s*)two")) + }) + }) + }) +}) diff --git a/integration/v7/selfcontained/logout_command_test.go b/integration/v7/selfcontained/logout_command_test.go new file mode 100644 index 00000000000..55e53f35a5d --- /dev/null +++ b/integration/v7/selfcontained/logout_command_test.go @@ -0,0 +1,29 @@ +package selfcontained_test + +import ( + "code.cloudfoundry.org/cli/integration/helpers" + "code.cloudfoundry.org/cli/util/configv3" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gexec" +) + +var _ = Describe("cf logout", func() { + BeforeEach(func() { + helpers.SetConfig(func(config *configv3.Config) { + config.ConfigFile.CFOnK8s.Enabled = true + config.ConfigFile.CFOnK8s.AuthInfo = "something" + }) + }) + + JustBeforeEach(func() { + Eventually(helpers.CF("logout")).Should(gexec.Exit(0)) + }) + + It("clears the auth-info", func() { + Expect(loadConfig().CFOnK8s).To(Equal(configv3.CFOnK8s{ + Enabled: true, + AuthInfo: "", + })) + }) +}) diff --git a/integration/v7/selfcontained/selfcontained_suite_test.go b/integration/v7/selfcontained/selfcontained_suite_test.go new file mode 100644 index 00000000000..403915d2aed --- /dev/null +++ b/integration/v7/selfcontained/selfcontained_suite_test.go @@ -0,0 +1,113 @@ +package selfcontained_test + +import ( + "bytes" + "crypto/rand" + "crypto/rsa" + "encoding/base64" + "encoding/json" + "io/ioutil" + "os" + "path/filepath" + "testing" + "time" + + "code.cloudfoundry.org/cli/integration/helpers" + "code.cloudfoundry.org/cli/integration/v7/selfcontained/fake" + "code.cloudfoundry.org/cli/util/configv3" + "github.com/SermoDigital/jose/crypto" + "github.com/SermoDigital/jose/jws" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "gopkg.in/yaml.v2" + apiv1 "k8s.io/client-go/tools/clientcmd/api/v1" +) + +var ( + homeDir string + apiServer *fake.CFAPI + env helpers.CFEnv + token []byte +) + +func TestSelfcontained(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Selfcontained Suite") +} + +var _ = BeforeEach(func() { + homeDir = helpers.SetHomeDir() + apiServer = fake.NewCFAPI() + helpers.SetConfig(func(config *configv3.Config) { + config.ConfigFile.Target = apiServer.URL() + }) + + keyPair, err := rsa.GenerateKey(rand.Reader, 2048) + Expect(err).NotTo(HaveOccurred()) + + jwt := jws.NewJWT(jws.Claims{ + "exp": time.Now().Add(time.Hour).Unix(), + }, crypto.SigningMethodRS256) + token, err = jwt.Serialize(keyPair) + Expect(err).NotTo(HaveOccurred()) +}) + +var _ = AfterEach(func() { + apiServer.Close() + helpers.DestroyHomeDir(homeDir) +}) + +func loadConfig() configv3.JSONConfig { + rawConfig, err := ioutil.ReadFile(filepath.Join(homeDir, ".cf", "config.json")) + Expect(err).NotTo(HaveOccurred()) + + var configFile configv3.JSONConfig + Expect(json.Unmarshal(rawConfig, &configFile)).To(Succeed()) + + return configFile +} + +func storeKubeConfig(kubeconfig apiv1.Config, kubeConfigPath string) { + Expect(os.MkdirAll(filepath.Dir(kubeConfigPath), 0o755)).To(Succeed()) + kubeConfigFile, err := os.OpenFile(kubeConfigPath, os.O_CREATE|os.O_WRONLY, 0o755) + Expect(kubeConfigFile.Truncate(0)).To(Succeed()) + Expect(err).NotTo(HaveOccurred()) + + // we need to serialise the config to JSON as the Config type only has json annotations (and no yaml ones) + // However, during json serialisation, byte arrays are base64 encoded which is not a desired side effect. + // In order to address this, we base64 decode them in advance + kubeconfig = base64DecodeClientCertByteArrays(kubeconfig) + var buf bytes.Buffer + err = json.NewEncoder(&buf).Encode(kubeconfig) + Expect(err).NotTo(HaveOccurred()) + + var configmap map[string]interface{} + err = json.Unmarshal(buf.Bytes(), &configmap) + Expect(err).NotTo(HaveOccurred()) + + // now we can save the config as yaml + err = yaml.NewEncoder(kubeConfigFile).Encode(configmap) + Expect(err).NotTo(HaveOccurred()) + Expect(kubeConfigFile.Close()).To(Succeed()) +} + +func base64DecodeClientCertByteArrays(kubeconfig apiv1.Config) apiv1.Config { + decodedAuthInfos := []apiv1.NamedAuthInfo{} + for _, authInfo := range kubeconfig.AuthInfos { + if len(authInfo.AuthInfo.ClientCertificateData) > 0 { + decodedCertData, err := base64.StdEncoding.DecodeString(string(authInfo.AuthInfo.ClientCertificateData)) + Expect(err).NotTo(HaveOccurred()) + authInfo.AuthInfo.ClientCertificateData = decodedCertData + } + if len(authInfo.AuthInfo.ClientKeyData) > 0 { + decodedKeyData, err := base64.StdEncoding.DecodeString(string(authInfo.AuthInfo.ClientKeyData)) + Expect(err).NotTo(HaveOccurred()) + authInfo.AuthInfo.ClientKeyData = decodedKeyData + } + + decodedAuthInfos = append(decodedAuthInfos, authInfo) + } + + kubeconfig.AuthInfos = decodedAuthInfos + return kubeconfig +} diff --git a/resources/user_resource.go b/resources/user_resource.go index cc6d9c6fa50..602aaa67919 100644 --- a/resources/user_resource.go +++ b/resources/user_resource.go @@ -8,3 +8,8 @@ type User struct { PresentationName string `json:"presentation_name"` Origin string `json:"origin"` } + +type K8sUser struct { + Name string `json:"name"` + Kind string `json:"kind"` +} diff --git a/util/configv3/config.go b/util/configv3/config.go index eeb6da99ea9..c6afb35ff5d 100644 --- a/util/configv3/config.go +++ b/util/configv3/config.go @@ -8,6 +8,13 @@ import ( "code.cloudfoundry.org/cli/version" ) +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . UserConfig + +type UserConfig interface { + CurrentUser() (User, error) + CurrentUserName() (string, error) +} + // Config combines the settings taken from the .cf/config.json, os.ENV, and the // plugin config. type Config struct { @@ -24,6 +31,8 @@ type Config struct { detectedSettings detectedSettings pluginsConfig PluginsConfig + + UserConfig } // BinaryVersion is the current version of the CF binary. @@ -97,3 +106,7 @@ func (config *Config) Verbose() (bool, []string) { return verbose, filePath } + +func (config *Config) SetKubernetesAuthInfo(authInfo string) { + config.ConfigFile.CFOnK8s.AuthInfo = authInfo +} diff --git a/util/configv3/config_test.go b/util/configv3/config_test.go index a646536f20a..b8f6e35aff2 100644 --- a/util/configv3/config_test.go +++ b/util/configv3/config_test.go @@ -3,8 +3,7 @@ package configv3_test import ( "os" - . "code.cloudfoundry.org/cli/util/configv3" - + "code.cloudfoundry.org/cli/util/configv3" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) @@ -12,7 +11,7 @@ import ( var _ = Describe("Config", func() { var ( homeDir string - config *Config + config *configv3.Config ) BeforeEach(func() { @@ -28,7 +27,7 @@ var _ = Describe("Config", func() { Expect(os.Setenv("FORCE_TTY", "true")).ToNot(HaveOccurred()) var err error - config, err = LoadConfig() + config, err = configv3.LoadConfig() Expect(err).ToNot(HaveOccurred()) Expect(config).ToNot(BeNil()) }) @@ -41,4 +40,20 @@ var _ = Describe("Config", func() { Expect(config.IsTTY()).To(BeTrue()) }) }) + + Describe("SetKubernetesAuthInfo", func() { + BeforeEach(func() { + var err error + config, err = configv3.LoadConfig() + Expect(err).NotTo(HaveOccurred()) + }) + + JustBeforeEach(func() { + config.SetKubernetesAuthInfo("k8s-auth") + }) + + It("sets the cf-on-k8s auth info", func() { + Expect(config.ConfigFile.CFOnK8s.AuthInfo).To(Equal("k8s-auth")) + }) + }) }) diff --git a/util/configv3/configv3fakes/fake_user_config.go b/util/configv3/configv3fakes/fake_user_config.go new file mode 100644 index 00000000000..72198fbd8a0 --- /dev/null +++ b/util/configv3/configv3fakes/fake_user_config.go @@ -0,0 +1,175 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package configv3fakes + +import ( + "sync" + + "code.cloudfoundry.org/cli/util/configv3" +) + +type FakeUserConfig struct { + CurrentUserStub func() (configv3.User, error) + currentUserMutex sync.RWMutex + currentUserArgsForCall []struct { + } + currentUserReturns struct { + result1 configv3.User + result2 error + } + currentUserReturnsOnCall map[int]struct { + result1 configv3.User + result2 error + } + CurrentUserNameStub func() (string, error) + currentUserNameMutex sync.RWMutex + currentUserNameArgsForCall []struct { + } + currentUserNameReturns struct { + result1 string + result2 error + } + currentUserNameReturnsOnCall map[int]struct { + result1 string + result2 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeUserConfig) CurrentUser() (configv3.User, error) { + fake.currentUserMutex.Lock() + ret, specificReturn := fake.currentUserReturnsOnCall[len(fake.currentUserArgsForCall)] + fake.currentUserArgsForCall = append(fake.currentUserArgsForCall, struct { + }{}) + fake.recordInvocation("CurrentUser", []interface{}{}) + fake.currentUserMutex.Unlock() + if fake.CurrentUserStub != nil { + return fake.CurrentUserStub() + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.currentUserReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeUserConfig) CurrentUserCallCount() int { + fake.currentUserMutex.RLock() + defer fake.currentUserMutex.RUnlock() + return len(fake.currentUserArgsForCall) +} + +func (fake *FakeUserConfig) CurrentUserCalls(stub func() (configv3.User, error)) { + fake.currentUserMutex.Lock() + defer fake.currentUserMutex.Unlock() + fake.CurrentUserStub = stub +} + +func (fake *FakeUserConfig) CurrentUserReturns(result1 configv3.User, result2 error) { + fake.currentUserMutex.Lock() + defer fake.currentUserMutex.Unlock() + fake.CurrentUserStub = nil + fake.currentUserReturns = struct { + result1 configv3.User + result2 error + }{result1, result2} +} + +func (fake *FakeUserConfig) CurrentUserReturnsOnCall(i int, result1 configv3.User, result2 error) { + fake.currentUserMutex.Lock() + defer fake.currentUserMutex.Unlock() + fake.CurrentUserStub = nil + if fake.currentUserReturnsOnCall == nil { + fake.currentUserReturnsOnCall = make(map[int]struct { + result1 configv3.User + result2 error + }) + } + fake.currentUserReturnsOnCall[i] = struct { + result1 configv3.User + result2 error + }{result1, result2} +} + +func (fake *FakeUserConfig) CurrentUserName() (string, error) { + fake.currentUserNameMutex.Lock() + ret, specificReturn := fake.currentUserNameReturnsOnCall[len(fake.currentUserNameArgsForCall)] + fake.currentUserNameArgsForCall = append(fake.currentUserNameArgsForCall, struct { + }{}) + fake.recordInvocation("CurrentUserName", []interface{}{}) + fake.currentUserNameMutex.Unlock() + if fake.CurrentUserNameStub != nil { + return fake.CurrentUserNameStub() + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.currentUserNameReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeUserConfig) CurrentUserNameCallCount() int { + fake.currentUserNameMutex.RLock() + defer fake.currentUserNameMutex.RUnlock() + return len(fake.currentUserNameArgsForCall) +} + +func (fake *FakeUserConfig) CurrentUserNameCalls(stub func() (string, error)) { + fake.currentUserNameMutex.Lock() + defer fake.currentUserNameMutex.Unlock() + fake.CurrentUserNameStub = stub +} + +func (fake *FakeUserConfig) CurrentUserNameReturns(result1 string, result2 error) { + fake.currentUserNameMutex.Lock() + defer fake.currentUserNameMutex.Unlock() + fake.CurrentUserNameStub = nil + fake.currentUserNameReturns = struct { + result1 string + result2 error + }{result1, result2} +} + +func (fake *FakeUserConfig) CurrentUserNameReturnsOnCall(i int, result1 string, result2 error) { + fake.currentUserNameMutex.Lock() + defer fake.currentUserNameMutex.Unlock() + fake.CurrentUserNameStub = nil + if fake.currentUserNameReturnsOnCall == nil { + fake.currentUserNameReturnsOnCall = make(map[int]struct { + result1 string + result2 error + }) + } + fake.currentUserNameReturnsOnCall[i] = struct { + result1 string + result2 error + }{result1, result2} +} + +func (fake *FakeUserConfig) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.currentUserMutex.RLock() + defer fake.currentUserMutex.RUnlock() + fake.currentUserNameMutex.RLock() + defer fake.currentUserNameMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeUserConfig) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ configv3.UserConfig = new(FakeUserConfig) diff --git a/util/configv3/default_user_config.go b/util/configv3/default_user_config.go new file mode 100644 index 00000000000..f2d96dfb2a6 --- /dev/null +++ b/util/configv3/default_user_config.go @@ -0,0 +1,58 @@ +package configv3 + +import ( + "github.com/SermoDigital/jose/jws" +) + +type DefaultUserConfig struct { + // ConfigFile stores the configuration from the .cf/config + ConfigFile *JSONConfig +} + +// CurrentUser returns user information decoded from the JWT access token in +// .cf/config.json. +func (config DefaultUserConfig) CurrentUser() (User, error) { + return decodeUserFromJWT(config.ConfigFile.AccessToken) +} + +// CurrentUserName returns the name of a user as returned by CurrentUser() +func (config DefaultUserConfig) CurrentUserName() (string, error) { + user, err := config.CurrentUser() + if err != nil { + return "", err + } + return user.Name, nil +} + +func decodeUserFromJWT(accessToken string) (User, error) { + if accessToken == "" { + return User{}, nil + } + + token, err := jws.ParseJWT([]byte(accessToken[7:])) + if err != nil { + return User{}, err + } + + claims := token.Claims() + + var name, GUID, origin string + var isClient bool + if claims.Has("user_name") { + name = claims.Get("user_name").(string) + GUID = claims.Get("user_id").(string) + origin = claims.Get("origin").(string) + isClient = false + } else { + name = claims.Get("client_id").(string) + GUID = name + isClient = true + } + + return User{ + Name: name, + GUID: GUID, + Origin: origin, + IsClient: isClient, + }, nil +} diff --git a/util/configv3/default_user_config_test.go b/util/configv3/default_user_config_test.go new file mode 100644 index 00000000000..350a94b6ff0 --- /dev/null +++ b/util/configv3/default_user_config_test.go @@ -0,0 +1,98 @@ +package configv3_test + +import ( + "code.cloudfoundry.org/cli/util/configv3" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("DefaultUserConfig", func() { + var config configv3.DefaultUserConfig + + Describe("CurrentUser", func() { + When("using client credentials and the user token is set", func() { + It("returns the user", func() { + config = configv3.DefaultUserConfig{ + ConfigFile: &configv3.JSONConfig{ + AccessToken: AccessTokenForClientUsers, + }, + } + user, err := config.CurrentUser() + Expect(err).ToNot(HaveOccurred()) + Expect(user).To(Equal(configv3.User{ + Name: "potato-face", + GUID: "potato-face", + IsClient: true, + })) + }) + }) + + When("using user/password and the user token is set", func() { + It("returns the user", func() { + config = configv3.DefaultUserConfig{ + ConfigFile: &configv3.JSONConfig{ + AccessToken: AccessTokenForHumanUsers, + }, + } + + user, err := config.CurrentUser() + Expect(err).ToNot(HaveOccurred()) + Expect(user).To(Equal(configv3.User{ + Name: "admin", + GUID: "9519be3e-44d9-40d0-ab9a-f4ace11df159", + Origin: "uaa", + IsClient: false, + })) + }) + }) + + When("the user token is blank", func() { + It("returns the user", func() { + config = configv3.DefaultUserConfig{ConfigFile: &configv3.JSONConfig{}} + + user, err := config.CurrentUser() + Expect(err).ToNot(HaveOccurred()) + Expect(user).To(Equal(configv3.User{})) + }) + }) + }) + + Describe("CurrentUserName", func() { + When("using client credentials and the user token is set", func() { + It("returns the username", func() { + config = configv3.DefaultUserConfig{ + ConfigFile: &configv3.JSONConfig{ + AccessToken: AccessTokenForClientUsers, + }, + } + + username, err := config.CurrentUserName() + Expect(err).ToNot(HaveOccurred()) + Expect(username).To(Equal("potato-face")) + }) + }) + + When("using user/password and the user token is set", func() { + It("returns the username", func() { + config = configv3.DefaultUserConfig{ + ConfigFile: &configv3.JSONConfig{ + AccessToken: AccessTokenForHumanUsers, + }, + } + + username, err := config.CurrentUserName() + Expect(err).ToNot(HaveOccurred()) + Expect(username).To(Equal("admin")) + }) + }) + + When("the user token is blank", func() { + It("returns an empty string", func() { + config = configv3.DefaultUserConfig{ConfigFile: &configv3.JSONConfig{}} + username, err := config.CurrentUserName() + Expect(err).ToNot(HaveOccurred()) + Expect(username).To(BeEmpty()) + }) + }) + }) +}) diff --git a/util/configv3/dynamic_user_config.go b/util/configv3/dynamic_user_config.go new file mode 100644 index 00000000000..86c6ea538fb --- /dev/null +++ b/util/configv3/dynamic_user_config.go @@ -0,0 +1,22 @@ +package configv3 + +type DynamicUserConfig struct { + ConfigFile *JSONConfig + DefaultUserConfig UserConfig + KubernetesUserConfig UserConfig +} + +func (config DynamicUserConfig) CurrentUser() (User, error) { + return config.pickConfig().CurrentUser() +} + +func (config DynamicUserConfig) CurrentUserName() (string, error) { + return config.pickConfig().CurrentUserName() +} + +func (config DynamicUserConfig) pickConfig() UserConfig { + if config.ConfigFile.CFOnK8s.Enabled { + return config.KubernetesUserConfig + } + return config.DefaultUserConfig +} diff --git a/util/configv3/dynamic_user_config_test.go b/util/configv3/dynamic_user_config_test.go new file mode 100644 index 00000000000..907250acb10 --- /dev/null +++ b/util/configv3/dynamic_user_config_test.go @@ -0,0 +1,137 @@ +package configv3_test + +import ( + "errors" + + "code.cloudfoundry.org/cli/util/configv3" + "code.cloudfoundry.org/cli/util/configv3/configv3fakes" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("DynamicUserConfig", func() { + var ( + fakeDefaultUserConfig *configv3fakes.FakeUserConfig + fakeKubernetesUserConfig *configv3fakes.FakeUserConfig + jsonConfig *configv3.JSONConfig + dynamicUserConfig configv3.DynamicUserConfig + err error + ) + + BeforeEach(func() { + fakeDefaultUserConfig = new(configv3fakes.FakeUserConfig) + fakeDefaultUserConfig.CurrentUserReturns(configv3.User{Name: "default-user"}, nil) + fakeDefaultUserConfig.CurrentUserNameReturns("default-user", nil) + + fakeKubernetesUserConfig = new(configv3fakes.FakeUserConfig) + fakeKubernetesUserConfig.CurrentUserReturns(configv3.User{Name: "kubernetes-user"}, nil) + fakeKubernetesUserConfig.CurrentUserNameReturns("kubernetes-user", nil) + + jsonConfig = &configv3.JSONConfig{} + dynamicUserConfig = configv3.DynamicUserConfig{ + ConfigFile: jsonConfig, + DefaultUserConfig: fakeDefaultUserConfig, + KubernetesUserConfig: fakeKubernetesUserConfig, + } + }) + + Describe("CurrentUser", func() { + var currentUser configv3.User + + JustBeforeEach(func() { + currentUser, err = dynamicUserConfig.CurrentUser() + }) + + When("using a default config", func() { + BeforeEach(func() { + jsonConfig.CFOnK8s.Enabled = false + }) + + It("delegates to the default UserConfig", func() { + Expect(err).NotTo(HaveOccurred()) + Expect(currentUser.Name).To(Equal("default-user")) + }) + + When("the default UserConfig fails", func() { + BeforeEach(func() { + fakeDefaultUserConfig.CurrentUserReturns(configv3.User{}, errors.New("current-user-err")) + }) + + It("returns the error", func() { + Expect(err).To(MatchError("current-user-err")) + }) + }) + }) + + When("using a Kubernetes config", func() { + BeforeEach(func() { + jsonConfig.CFOnK8s.Enabled = true + }) + + It("delegates to the Kubernetes UserConfig", func() { + Expect(err).NotTo(HaveOccurred()) + Expect(currentUser.Name).To(Equal("kubernetes-user")) + }) + + When("the Kubernetes UserConfig fails", func() { + BeforeEach(func() { + fakeKubernetesUserConfig.CurrentUserReturns(configv3.User{}, errors.New("current-user-err")) + }) + + It("returns the error", func() { + Expect(err).To(MatchError("current-user-err")) + }) + }) + }) + }) + + Describe("CurrentUserName", func() { + var currentUserName string + + JustBeforeEach(func() { + currentUserName, err = dynamicUserConfig.CurrentUserName() + }) + + When("using a default config", func() { + BeforeEach(func() { + jsonConfig.CFOnK8s.Enabled = false + }) + + It("delegates to the default UserConfig", func() { + Expect(err).NotTo(HaveOccurred()) + Expect(currentUserName).To(Equal("default-user")) + }) + + When("the default UserConfig fails", func() { + BeforeEach(func() { + fakeDefaultUserConfig.CurrentUserNameReturns("", errors.New("current-username-err")) + }) + + It("returns the error", func() { + Expect(err).To(MatchError("current-username-err")) + }) + }) + }) + + When("using a Kubernetes config", func() { + BeforeEach(func() { + jsonConfig.CFOnK8s.Enabled = true + }) + + It("delegates to the Kubernetes UserConfig", func() { + Expect(err).NotTo(HaveOccurred()) + Expect(currentUserName).To(Equal("kubernetes-user")) + }) + + When("the Kubernetes UserConfig fails", func() { + BeforeEach(func() { + fakeKubernetesUserConfig.CurrentUserNameReturns("", errors.New("current-username-err")) + }) + + It("returns the error", func() { + Expect(err).To(MatchError("current-username-err")) + }) + }) + }) + }) +}) diff --git a/util/configv3/json_config.go b/util/configv3/json_config.go index ff147958810..c672de98ad9 100644 --- a/util/configv3/json_config.go +++ b/util/configv3/json_config.go @@ -2,8 +2,6 @@ package configv3 import ( "time" - - "github.com/SermoDigital/jose/jws" ) // JSONConfig represents .cf/config.json. @@ -12,6 +10,7 @@ type JSONConfig struct { APIVersion string `json:"APIVersion"` AsyncTimeout int `json:"AsyncTimeout"` AuthorizationEndpoint string `json:"AuthorizationEndpoint"` + CFOnK8s CFOnK8s `json:"CFOnK8s"` ColorEnabled string `json:"ColorEnabled"` ConfigVersion int `json:"ConfigVersion"` DopplerEndpoint string `json:"DopplerEndPoint"` @@ -71,21 +70,6 @@ func (config *Config) AuthorizationEndpoint() string { return config.ConfigFile.AuthorizationEndpoint } -// CurrentUser returns user information decoded from the JWT access token in -// .cf/config.json. -func (config *Config) CurrentUser() (User, error) { - return decodeUserFromJWT(config.ConfigFile.AccessToken) -} - -// CurrentUserName returns the name of a user as returned by CurrentUser() -func (config *Config) CurrentUserName() (string, error) { - user, err := config.CurrentUser() - if err != nil { - return "", err - } - return user.Name, nil -} - // HasTargetedOrganization returns true if the organization is set. func (config *Config) HasTargetedOrganization() bool { return config.ConfigFile.TargetedOrganization.GUID != "" @@ -192,6 +176,7 @@ type TargetInformationArgs struct { Routing string SkipSSLValidation bool UAA string + CFOnK8s bool } // SetTargetInformation sets the currently targeted CC API and related other @@ -213,6 +198,8 @@ func (config *Config) SetTargetInformation(args TargetInformationArgs) { // ever read from there. config.ConfigFile.AuthorizationEndpoint = args.Auth + config.ConfigFile.CFOnK8s.Enabled = args.CFOnK8s + config.UnsetOrganizationAndSpaceInformation() } @@ -317,9 +304,9 @@ func (config *Config) UnsetUserInformation() { config.SetRefreshToken("") config.SetUAAGrantType("") config.SetUAAClientCredentials(DefaultUAAOAuthClient, DefaultUAAOAuthClientSecret) + config.SetKubernetesAuthInfo("") config.UnsetOrganizationAndSpaceInformation() - } // V7SetSpaceInformation sets the currently targeted space. @@ -327,36 +314,3 @@ func (config *Config) V7SetSpaceInformation(guid string, name string) { config.ConfigFile.TargetedSpace.GUID = guid config.ConfigFile.TargetedSpace.Name = name } - -func decodeUserFromJWT(accessToken string) (User, error) { - if accessToken == "" { - return User{}, nil - } - - token, err := jws.ParseJWT([]byte(accessToken[7:])) - if err != nil { - return User{}, err - } - - claims := token.Claims() - - var name, GUID, origin string - var isClient bool - if claims.Has("user_name") { - name = claims.Get("user_name").(string) - GUID = claims.Get("user_id").(string) - origin = claims.Get("origin").(string) - isClient = false - } else { - name = claims.Get("client_id").(string) - GUID = name - isClient = true - } - - return User{ - Name: name, - GUID: GUID, - Origin: origin, - IsClient: isClient, - }, nil -} diff --git a/util/configv3/json_config_test.go b/util/configv3/json_config_test.go index 9662c878252..19c16b1c420 100644 --- a/util/configv3/json_config_test.go +++ b/util/configv3/json_config_test.go @@ -4,6 +4,7 @@ import ( "fmt" "time" + "code.cloudfoundry.org/cli/util/configv3" . "code.cloudfoundry.org/cli/util/configv3" . "github.com/onsi/ginkgo" @@ -50,92 +51,6 @@ var _ = Describe("JSONConfig", func() { }) }) - Describe("CurrentUser", func() { - When("using client credentials and the user token is set", func() { - It("returns the user", func() { - config = &Config{ - ConfigFile: JSONConfig{ - AccessToken: AccessTokenForClientUsers, - }, - } - user, err := config.CurrentUser() - Expect(err).ToNot(HaveOccurred()) - Expect(user).To(Equal(User{ - Name: "potato-face", - GUID: "potato-face", - IsClient: true, - })) - }) - }) - - When("using user/password and the user token is set", func() { - It("returns the user", func() { - config = &Config{ - ConfigFile: JSONConfig{ - AccessToken: AccessTokenForHumanUsers, - }, - } - - user, err := config.CurrentUser() - Expect(err).ToNot(HaveOccurred()) - Expect(user).To(Equal(User{ - Name: "admin", - GUID: "9519be3e-44d9-40d0-ab9a-f4ace11df159", - Origin: "uaa", - IsClient: false, - })) - }) - }) - - When("the user token is blank", func() { - It("returns the user", func() { - config = new(Config) - user, err := config.CurrentUser() - Expect(err).ToNot(HaveOccurred()) - Expect(user).To(Equal(User{})) - }) - }) - }) - - Describe("CurrentUserName", func() { - When("using client credentials and the user token is set", func() { - It("returns the username", func() { - config = &Config{ - ConfigFile: JSONConfig{ - AccessToken: AccessTokenForClientUsers, - }, - } - - username, err := config.CurrentUserName() - Expect(err).ToNot(HaveOccurred()) - Expect(username).To(Equal("potato-face")) - }) - }) - - When("using user/password and the user token is set", func() { - It("returns the username", func() { - config = &Config{ - ConfigFile: JSONConfig{ - AccessToken: AccessTokenForHumanUsers, - }, - } - - username, err := config.CurrentUserName() - Expect(err).ToNot(HaveOccurred()) - Expect(username).To(Equal("admin")) - }) - }) - - When("the user token is blank", func() { - It("returns an empty string", func() { - config = new(Config) - username, err := config.CurrentUserName() - Expect(err).ToNot(HaveOccurred()) - Expect(username).To(BeEmpty()) - }) - }) - }) - Describe("HasTargetedOrganization", func() { When("an organization is targeted", func() { It("returns true", func() { @@ -307,6 +222,7 @@ var _ = Describe("JSONConfig", func() { LogCache: "https://log-cache.foo.com", Routing: "https://api.foo.com/routing", SkipSSLValidation: true, + CFOnK8s: true, }) Expect(config.ConfigFile.Target).To(Equal("https://api.foo.com")) @@ -323,6 +239,8 @@ var _ = Describe("JSONConfig", func() { Expect(config.ConfigFile.TargetedSpace.GUID).To(BeEmpty()) Expect(config.ConfigFile.TargetedSpace.Name).To(BeEmpty()) Expect(config.ConfigFile.TargetedSpace.AllowSSH).To(BeFalse()) + + Expect(config.ConfigFile.CFOnK8s.Enabled).To(BeTrue()) }) }) @@ -561,6 +479,7 @@ var _ = Describe("JSONConfig", func() { config.SetUAAClientCredentials("some-client", "some-client-secret") config.SetOrganizationInformation("some-org-guid", "some-org") config.SetSpaceInformation("guid-value-1", "my-org-name", true) + config.SetKubernetesAuthInfo("some-auth-info") }) It("resets all user information", func() { @@ -576,6 +495,48 @@ var _ = Describe("JSONConfig", func() { Expect(config.ConfigFile.UAAGrantType).To(BeEmpty()) Expect(config.ConfigFile.UAAOAuthClient).To(Equal(DefaultUAAOAuthClient)) Expect(config.ConfigFile.UAAOAuthClientSecret).To(Equal(DefaultUAAOAuthClientSecret)) + Expect(config.ConfigFile.CFOnK8s.AuthInfo).To(BeEmpty()) + }) + }) + + When("using CF-on-K8s", func() { + var err error + + BeforeEach(func() { + rawConfig := fmt.Sprintf(`{ "CFOnK8s": {"Enabled": true, "AuthInfo": "auth-info-name"}, "ConfigVersion": %d }`, CurrentConfigVersion) + + setConfig(homeDir, rawConfig) + + config, err = LoadConfig() + Expect(err).ToNot(HaveOccurred()) + Expect(config).ToNot(BeNil()) + }) + + Describe("CurrentUser", func() { + var user configv3.User + + JustBeforeEach(func() { + user, err = config.CurrentUser() + }) + + It("returns a user with the auth-info name", func() { + Expect(err).NotTo(HaveOccurred()) + Expect(user.Name).To(Equal("auth-info-name")) + Expect(user.GUID).To(BeEmpty()) + }) + }) + + Describe("CurrentUserName", func() { + var userName string + + JustBeforeEach(func() { + userName, err = config.CurrentUserName() + }) + + It("returns the auth-info name", func() { + Expect(err).NotTo(HaveOccurred()) + Expect(userName).To(Equal("auth-info-name")) + }) }) }) }) diff --git a/util/configv3/k8s.go b/util/configv3/k8s.go new file mode 100644 index 00000000000..e7e69aab33c --- /dev/null +++ b/util/configv3/k8s.go @@ -0,0 +1,10 @@ +package configv3 + +type CFOnK8s struct { + Enabled bool `json:"Enabled"` + AuthInfo string `json:"AuthInfo"` +} + +func (config *Config) IsCFOnK8s() bool { + return config.ConfigFile.CFOnK8s.Enabled +} diff --git a/util/configv3/k8s_test.go b/util/configv3/k8s_test.go new file mode 100644 index 00000000000..2b6dfd6b209 --- /dev/null +++ b/util/configv3/k8s_test.go @@ -0,0 +1,34 @@ +package configv3_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "code.cloudfoundry.org/cli/util/configv3" +) + +var _ = Describe("K8s", func() { + var config configv3.Config + + BeforeEach(func() { + config = configv3.Config{} + }) + + Describe("IsCFOnK8s", func() { + It("returns false by default", func() { + Expect(config.IsCFOnK8s()).To(BeFalse()) + }) + + When("the config is pointed to cf-on-k8s", func() { + BeforeEach(func() { + config.ConfigFile.CFOnK8s = configv3.CFOnK8s{ + Enabled: true, + } + }) + + It("returns true", func() { + Expect(config.IsCFOnK8s()).To(BeTrue()) + }) + }) + }) +}) diff --git a/util/configv3/kubernetes_user_config.go b/util/configv3/kubernetes_user_config.go new file mode 100644 index 00000000000..0ae5f485cfa --- /dev/null +++ b/util/configv3/kubernetes_user_config.go @@ -0,0 +1,17 @@ +package configv3 + +type KubernetesUserConfig struct { + // ConfigFile stores the configuration from the .cf/config + ConfigFile *JSONConfig +} + +// CurrentUser returns user information decoded from the JWT access token in +// .cf/config.json. +func (config KubernetesUserConfig) CurrentUser() (User, error) { + return User{Name: config.ConfigFile.CFOnK8s.AuthInfo}, nil +} + +// CurrentUserName returns the name of a user as returned by CurrentUser() +func (config KubernetesUserConfig) CurrentUserName() (string, error) { + return config.ConfigFile.CFOnK8s.AuthInfo, nil +} diff --git a/util/configv3/kubernetes_user_config_test.go b/util/configv3/kubernetes_user_config_test.go new file mode 100644 index 00000000000..6229df54ebd --- /dev/null +++ b/util/configv3/kubernetes_user_config_test.go @@ -0,0 +1,50 @@ +package configv3_test + +import ( + "code.cloudfoundry.org/cli/util/configv3" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("KubernetesUserConfig", func() { + var ( + config configv3.KubernetesUserConfig + err error + ) + + BeforeEach(func() { + config = configv3.KubernetesUserConfig{ + ConfigFile: &configv3.JSONConfig{ + CFOnK8s: configv3.CFOnK8s{ + AuthInfo: "kubernetes-user", + }, + }, + } + }) + + Describe("CurrentUser", func() { + var user configv3.User + + JustBeforeEach(func() { + user, err = config.CurrentUser() + }) + + It("returns the configured auth-info", func() { + Expect(err).NotTo(HaveOccurred()) + Expect(user).To(Equal(configv3.User{Name: "kubernetes-user"})) + }) + }) + + Describe("CurrentUserName", func() { + var userName string + + JustBeforeEach(func() { + userName, err = config.CurrentUserName() + }) + + It("returns the configured auth-info", func() { + Expect(err).NotTo(HaveOccurred()) + Expect(userName).To(Equal("kubernetes-user")) + }) + }) +}) diff --git a/util/configv3/load_config.go b/util/configv3/load_config.go index 73048820ab2..90470e2464d 100644 --- a/util/configv3/load_config.go +++ b/util/configv3/load_config.go @@ -166,6 +166,12 @@ func LoadConfig(flags ...FlagOverride) (*Config, error) { tty: isTTY, } + config.UserConfig = DynamicUserConfig{ + ConfigFile: &config.ConfigFile, + DefaultUserConfig: DefaultUserConfig{ConfigFile: &config.ConfigFile}, + KubernetesUserConfig: KubernetesUserConfig{ConfigFile: &config.ConfigFile}, + } + return &config, jsonError } From 034d929d7265565d3c7f3bb6f13608cc12acb068 Mon Sep 17 00:00:00 2001 From: Al Berez Date: Mon, 3 Jan 2022 10:30:50 -0800 Subject: [PATCH 010/248] Update BUILD_VERSION v8.1.0 --- BUILD_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD_VERSION b/BUILD_VERSION index ae9a76b9249..8104cabd36f 100644 --- a/BUILD_VERSION +++ b/BUILD_VERSION @@ -1 +1 @@ -8.0.0 +8.1.0 From d7135f357af3150743152679f68411bf4d072484 Mon Sep 17 00:00:00 2001 From: MerricdeLauney Date: Mon, 20 Dec 2021 07:41:45 -0800 Subject: [PATCH 011/248] Add space supporter to space users command (#2235) Space supporter is only available on certain versions of CAPI. To ensure space user command behavior is always being tested at the integration level, we created a new test that only would be run on newer versions of CAPI where the space supporter is able to be created and retrieved by this command. [#179982523] Co-authored-by: Mona Mohebbi --- .../ccversion/minimum_version.go | 3 +- command/v7/space_users_command.go | 1 + command/v7/space_users_command_test.go | 9 ++++++ .../v7/isolated/space_users_command_test.go | 31 +++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/api/cloudcontroller/ccversion/minimum_version.go b/api/cloudcontroller/ccversion/minimum_version.go index c6894444615..2f54e575fc0 100644 --- a/api/cloudcontroller/ccversion/minimum_version.go +++ b/api/cloudcontroller/ccversion/minimum_version.go @@ -11,5 +11,6 @@ const ( MinVersionCreateServiceBrokerV3 = "3.72.0" MinVersionCreateSpaceScopedServiceBrokerV3 = "3.75.0" - MinVersionHTTP2RoutingV3 = "3.104.0" + MinVersionHTTP2RoutingV3 = "3.104.0" + MinVersionSpaceSupporterV3 = "3.104.0" ) diff --git a/command/v7/space_users_command.go b/command/v7/space_users_command.go index d17029ec03c..149ddb9aa3a 100644 --- a/command/v7/space_users_command.go +++ b/command/v7/space_users_command.go @@ -58,6 +58,7 @@ func (cmd *SpaceUsersCommand) Execute(args []string) error { func (cmd SpaceUsersCommand) displaySpaceUsers(orgUsersByRoleType map[constant.RoleType][]resources.User) { cmd.displayRoleGroup(orgUsersByRoleType[constant.SpaceManagerRole], "SPACE MANAGER") cmd.displayRoleGroup(orgUsersByRoleType[constant.SpaceDeveloperRole], "SPACE DEVELOPER") + cmd.displayRoleGroup(orgUsersByRoleType[constant.SpaceSupporterRole], "SPACE SUPPORTER") cmd.displayRoleGroup(orgUsersByRoleType[constant.SpaceAuditorRole], "SPACE AUDITOR") } diff --git a/command/v7/space_users_command_test.go b/command/v7/space_users_command_test.go index 58b96fbca69..062e6ab69c8 100644 --- a/command/v7/space_users_command_test.go +++ b/command/v7/space_users_command_test.go @@ -167,6 +167,11 @@ var _ = Describe("space-users Command", func() { PresentationName: "billing-manager", GUID: "spaceDeveloper-guid", } + spaceSupporter := resources.User{ + Origin: "uaa", + PresentationName: "fred", + GUID: "spaceSupporter-guid", + } spaceAuditor := resources.User{ Origin: "uaa", PresentationName: "org-auditor", @@ -176,6 +181,7 @@ var _ = Describe("space-users Command", func() { spaceUsersByRole := map[constant.RoleType][]resources.User{ constant.SpaceManagerRole: {uaaAdmin, ldapAdmin, abbyUser, client}, constant.SpaceDeveloperRole: {spaceDeveloper}, + constant.SpaceSupporterRole: {spaceSupporter}, constant.SpaceAuditorRole: {spaceAuditor}, } @@ -199,6 +205,9 @@ var _ = Describe("space-users Command", func() { Expect(testUI.Out).To(Say(`\nSPACE DEVELOPER`)) Expect(testUI.Out).To(Say(`\n billing-manager \(uaa\)`)) Expect(testUI.Out).To(Say(`\n`)) + Expect(testUI.Out).To(Say(`\nSPACE SUPPORTER`)) + Expect(testUI.Out).To(Say(`\n fred \(uaa\)`)) + Expect(testUI.Out).To(Say(`\n`)) Expect(testUI.Out).To(Say(`\nSPACE AUDITOR`)) Expect(testUI.Out).To(Say(`\n org-auditor \(uaa\)`)) diff --git a/integration/v7/isolated/space_users_command_test.go b/integration/v7/isolated/space_users_command_test.go index c81293d4428..5d090b2f576 100644 --- a/integration/v7/isolated/space_users_command_test.go +++ b/integration/v7/isolated/space_users_command_test.go @@ -8,6 +8,7 @@ import ( . "github.com/onsi/gomega/gbytes" . "github.com/onsi/gomega/gexec" + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" "code.cloudfoundry.org/cli/integration/helpers" ) @@ -91,5 +92,35 @@ var _ = Describe("space-users command", func() { Eventually(session).Should(Exit(0)) }) }) + When("capi provides space supporter", func() { + var ( + spaceManagerUser string + spaceDeveloperUser string + spaceSupporterUser string + spaceAuditorUser1 string + ) + + BeforeEach(func() { + helpers.SkipIfVersionLessThan(ccversion.MinVersionSpaceSupporterV3) + spaceManagerUser, _ = helpers.CreateUserInSpaceRole(orgName, spaceName, "SpaceManager") + spaceDeveloperUser, _ = helpers.CreateUserInSpaceRole(orgName, spaceName, "SpaceDeveloper") + spaceSupporterUser, _ = helpers.CreateUserInSpaceRole(orgName, spaceName, "SpaceSupporter") + spaceAuditorUser1, _ = helpers.CreateUserInSpaceRole(orgName, spaceName, "SpaceAuditor") + }) + + It("prints the users in the target space under their roles", func() { + session := helpers.CF("space-users", orgName, spaceName) + Eventually(session).Should(Say("Getting users in org %s / space %s as %s", orgName, spaceName, adminUsername)) + Eventually(session).Should(Say("SPACE MANAGER")) + Eventually(session).Should(Say(`\s+%s \(uaa\)`, spaceManagerUser)) + Eventually(session).Should(Say("SPACE DEVELOPER")) + Eventually(session).Should(Say(`\s+%s \(uaa\)`, spaceDeveloperUser)) + Eventually(session).Should(Say("SPACE SUPPORTER")) + Eventually(session).Should(Say(`\s+%s \(uaa\)`, spaceSupporterUser)) + Eventually(session).Should(Say("SPACE AUDITOR")) + Eventually(session).Should(Say(`\s+%s \(uaa\)`, spaceAuditorUser1)) + Eventually(session).Should(Exit(0)) + }) + }) }) }) From 17692758672b20abb843a73d0645ba889b8ca061 Mon Sep 17 00:00:00 2001 From: Maria Shaldybin Date: Thu, 20 Jan 2022 00:35:24 +0000 Subject: [PATCH 012/248] Fix destination protocol flake in map-route test --- api/cloudcontroller/ccv3/route_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/cloudcontroller/ccv3/route_test.go b/api/cloudcontroller/ccv3/route_test.go index 351e27636d8..764b2787848 100644 --- a/api/cloudcontroller/ccv3/route_test.go +++ b/api/cloudcontroller/ccv3/route_test.go @@ -539,7 +539,7 @@ var _ = Describe("Route", func() { var ( routeGUID = "route-guid" appGUID = "app-guid" - destinationProtocol = "http2" + destinationProtocol string expectedBody string warnings Warnings executeErr error @@ -559,6 +559,7 @@ var _ = Describe("Route", func() { When("the request is successful", func() { BeforeEach(func() { + destinationProtocol = "http2" expectedBody = fmt.Sprintf(` { "destinations": [ From f316ed6ec2dab73eb256ef25da5107789b131a30 Mon Sep 17 00:00:00 2001 From: Sarah Weinstein Date: Tue, 30 Nov 2021 20:19:28 +0000 Subject: [PATCH 013/248] Consolidate version checking to use ccversion file We noticed the constant for minimum v3 versioning was not being used anywhere and also did not accurately reflect the minimum CAPI version required for the V8 CLI, which the CLI version that supports V3 only uses. We replaced it with the accurate minimum version based on a version checker that is being used in login and auth and consolidated references to only use the minimum version constant. Co-authored-by: Sarah Weinstein Co-authored-by: Mona Mohebbi --- api/cloudcontroller/ccversion/minimum_version.go | 2 +- command/v7/shared/version_checker.go | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/api/cloudcontroller/ccversion/minimum_version.go b/api/cloudcontroller/ccversion/minimum_version.go index 2f54e575fc0..524f740604f 100644 --- a/api/cloudcontroller/ccversion/minimum_version.go +++ b/api/cloudcontroller/ccversion/minimum_version.go @@ -2,7 +2,7 @@ package ccversion const ( MinSupportedV2ClientVersion = "2.128.0" - MinSupportedV3ClientVersion = "3.63.0" + MinSupportedClientVersionV8 = "3.99.0" MinVersionUpdateServiceNameWhenPlanNotVisibleV2 = "2.131.0" MinVersionUpdateServiceInstanceMaintenanceInfoV2 = "2.135.0" diff --git a/command/v7/shared/version_checker.go b/command/v7/shared/version_checker.go index 7a83be7c464..bfd35ec22e9 100644 --- a/command/v7/shared/version_checker.go +++ b/command/v7/shared/version_checker.go @@ -3,24 +3,23 @@ package shared import ( "fmt" + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" "github.com/blang/semver" ) -const minimumCCAPIVersionForV8 = "3.99.0" - func CheckCCAPIVersion(currentAPIVersion string) (string, error) { currentSemver, err := semver.Make(currentAPIVersion) if err != nil { return "", err } - minimumSemver, err := semver.Make(minimumCCAPIVersionForV8) + minimumSemver, err := semver.Make(ccversion.MinSupportedClientVersionV8) if err != nil { return "", err } if currentSemver.LT(minimumSemver) { - return fmt.Sprintf("\nWarning: Your targeted API's version (%s) is less than the minimum supported API version (%s). Some commands may not function correctly.", currentAPIVersion, minimumCCAPIVersionForV8), nil + return fmt.Sprintf("\nWarning: Your targeted API's version (%s) is less than the minimum supported API version (%s). Some commands may not function correctly.", currentAPIVersion, ccversion.MinSupportedClientVersionV8), nil } return "", nil From d5af40431b125d7f546ba521f4e39506afdeabf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Diego=20Gonz=C3=A1lez?= <25335192+jdgonzaleza@users.noreply.github.com> Date: Wed, 10 Nov 2021 15:51:24 -0500 Subject: [PATCH 014/248] [Feature] support HTTP/2 cf command (#2230) [reason] Renaming "protocol" column to "app-protocol" in the destination table of the cf route command Co-authored-by: Hector Calderon --- command/v7/route_command.go | 2 +- command/v7/route_command_test.go | 2 +- integration/v7/isolated/route_command_test.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/command/v7/route_command.go b/command/v7/route_command.go index 9e4aa0ba1a3..1ed64478ee6 100644 --- a/command/v7/route_command.go +++ b/command/v7/route_command.go @@ -116,7 +116,7 @@ func (cmd RouteCommand) displayDestinations(route resources.Route, appMap map[st cmd.UI.TranslateText("app"), cmd.UI.TranslateText("process"), cmd.UI.TranslateText("port"), - cmd.UI.TranslateText("protocol"), + cmd.UI.TranslateText("app-protocol"), }, } diff --git a/command/v7/route_command_test.go b/command/v7/route_command_test.go index 331ed929805..2249d13ee7a 100644 --- a/command/v7/route_command_test.go +++ b/command/v7/route_command_test.go @@ -220,7 +220,7 @@ var _ = Describe("route Command", func() { Expect(testUI.Out).To(Say(`protocol:\s+http`)) Expect(testUI.Out).To(Say(`\n`)) Expect(testUI.Out).To(Say(`Destinations:`)) - Expect(testUI.Out).To(Say(`\s+app\s+process\s+port\s+protocol`)) + Expect(testUI.Out).To(Say(`\s+app\s+process\s+port\s+app-protocol`)) Expect(testUI.Out).To(Say(`\s+app-name\s+web\s+8080\s+http1`)) Expect(testUI.Out).To(Say(`\s+other-app-name\s+web\s+1337\s+http2`)) diff --git a/integration/v7/isolated/route_command_test.go b/integration/v7/isolated/route_command_test.go index 4e8d109d2fc..85d50275c44 100644 --- a/integration/v7/isolated/route_command_test.go +++ b/integration/v7/isolated/route_command_test.go @@ -119,7 +119,7 @@ var _ = Describe("route command", func() { Eventually(session).Should(Say(`protocol:\s+http`)) Eventually(session).Should(Say(`\n`)) Eventually(session).Should(Say(`Destinations:`)) - Eventually(session).Should(Say(`\s+app\s+process\s+port\s+protocol`)) + Eventually(session).Should(Say(`\s+app\s+process\s+port\s+app-protocol`)) Eventually(session).Should(Exit(0)) }) @@ -167,7 +167,7 @@ var _ = Describe("route command", func() { Eventually(session).Should(Say(`protocol:\s+tcp`)) Eventually(session).Should(Say(`\n`)) Eventually(session).Should(Say(`Destinations:`)) - Eventually(session).Should(Say(`\s+app\s+process\s+port\s+protocol`)) + Eventually(session).Should(Say(`\s+app\s+process\s+port\s+app-protocol`)) Eventually(session).Should(Exit(0)) }) From a8b846e5893129f0adb0a6c8d186d442a84fc46b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Diego=20Gonz=C3=A1lez?= <25335192+jdgonzaleza@users.noreply.github.com> Date: Fri, 12 Nov 2021 14:45:50 -0500 Subject: [PATCH 015/248] [Feature] Rename flag to app-protocol in map-route (#2231) Currently the cli already has a flag named destination-protocol and in order to have consistency we need to rename it to app-protocol Co-authored-by: Hector Calderon --- command/v7/map_route_command.go | 20 ++++++++-------- command/v7/map_route_command_test.go | 24 +++++++++---------- .../v7/isolated/map_route_command_test.go | 10 ++++---- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/command/v7/map_route_command.go b/command/v7/map_route_command.go index a9a4afe1bae..c9ca6b381ac 100644 --- a/command/v7/map_route_command.go +++ b/command/v7/map_route_command.go @@ -8,11 +8,11 @@ import ( type MapRouteCommand struct { BaseCommand - RequiredArgs flag.AppDomain `positional-args:"yes"` - Hostname string `long:"hostname" short:"n" description:"Hostname for the HTTP route (required for shared domains)"` - Path flag.V7RoutePath `long:"path" description:"Path for the HTTP route"` - Port int `long:"port" description:"Port for the TCP route (default: random port)"` - DestinationProtocol string `long:"destination-protocol" description:"[Beta flag, subject to change] Protocol for the route destination (default: http1). Only applied to HTTP routes"` + RequiredArgs flag.AppDomain `positional-args:"yes"` + Hostname string `long:"hostname" short:"n" description:"Hostname for the HTTP route (required for shared domains)"` + Path flag.V7RoutePath `long:"path" description:"Path for the HTTP route"` + Port int `long:"port" description:"Port for the TCP route (default: random port)"` + AppProtocol string `long:"app-protocol" description:"[Beta flag, subject to change] Protocol for the route destination (default: http1). Only applied to HTTP routes"` relatedCommands interface{} `related_commands:"create-route, routes, unmap-route"` } @@ -20,7 +20,7 @@ type MapRouteCommand struct { func (cmd MapRouteCommand) Usage() string { return ` Map an HTTP route: - CF_NAME map-route APP_NAME DOMAIN [--hostname HOSTNAME] [--path PATH] [--destination-protocol PROTOCOL] + CF_NAME map-route APP_NAME DOMAIN [--hostname HOSTNAME] [--path PATH] [--app-protocol PROTOCOL] Map a TCP route: CF_NAME map-route APP_NAME DOMAIN [--port PORT]` @@ -31,7 +31,7 @@ func (cmd MapRouteCommand) Examples() string { CF_NAME map-route my-app example.com # example.com CF_NAME map-route my-app example.com --hostname myhost # myhost.example.com CF_NAME map-route my-app example.com --hostname myhost --path foo # myhost.example.com/foo -CF_NAME map-route my-app example.com --hostname myhost --destination-protocol http2 # myhost.example.com +CF_NAME map-route my-app example.com --hostname myhost --app-protocol http2 # myhost.example.com CF_NAME map-route my-app example.com --port 5000 # example.com:5000` } @@ -88,14 +88,14 @@ func (cmd MapRouteCommand) Execute(args []string) error { cmd.UI.DisplayOK() } - if cmd.DestinationProtocol != "" { + if cmd.AppProtocol != "" { cmd.UI.DisplayTextWithFlavor("Mapping route {{.URL}} to app {{.AppName}} with protocol {{.Protocol}} in org {{.OrgName}} / space {{.SpaceName}} as {{.User}}...", map[string]interface{}{ "URL": route.URL, "AppName": cmd.RequiredArgs.App, "User": user.Name, "SpaceName": cmd.Config.TargetedSpace().Name, "OrgName": cmd.Config.TargetedOrganization().Name, - "Protocol": cmd.DestinationProtocol, + "Protocol": cmd.AppProtocol, }) } else { @@ -121,7 +121,7 @@ func (cmd MapRouteCommand) Execute(args []string) error { cmd.UI.DisplayOK() return nil } - warnings, err = cmd.Actor.MapRoute(route.GUID, app.GUID, cmd.DestinationProtocol) + warnings, err = cmd.Actor.MapRoute(route.GUID, app.GUID, cmd.AppProtocol) cmd.UI.DisplayWarnings(warnings) if err != nil { return err diff --git a/command/v7/map_route_command_test.go b/command/v7/map_route_command_test.go index a2be30ebd57..3e7b111edeb 100644 --- a/command/v7/map_route_command_test.go +++ b/command/v7/map_route_command_test.go @@ -53,10 +53,10 @@ var _ = Describe("map-route Command", func() { spaceGUID = "some-space-guid" cmd = MapRouteCommand{ - RequiredArgs: flag.AppDomain{App: appName, Domain: domain}, - Hostname: hostname, - Path: flag.V7RoutePath{Path: path}, - DestinationProtocol: "http2", + RequiredArgs: flag.AppDomain{App: appName, Domain: domain}, + Hostname: hostname, + Path: flag.V7RoutePath{Path: path}, + AppProtocol: "http2", BaseCommand: BaseCommand{ UI: testUI, Config: fakeConfig, @@ -372,10 +372,10 @@ var _ = Describe("map-route Command", func() { Expect(actualPort).To(Equal(cmd.Port)) Expect(fakeActor.MapRouteCallCount()).To(Equal(1)) - actualRouteGUID, actualAppGUID, actualDestinationProtocol := fakeActor.MapRouteArgsForCall(0) + actualRouteGUID, actualAppGUID, actualAppProtocol := fakeActor.MapRouteArgsForCall(0) Expect(actualRouteGUID).To(Equal("route-guid")) Expect(actualAppGUID).To(Equal("app-guid")) - Expect(actualDestinationProtocol).To(Equal("http2")) + Expect(actualAppProtocol).To(Equal("http2")) }) }) @@ -411,10 +411,10 @@ var _ = Describe("map-route Command", func() { Expect(actualPort).To(Equal(cmd.Port)) Expect(fakeActor.MapRouteCallCount()).To(Equal(1)) - actualRouteGUID, actualAppGUID, actualDestinationProtocol := fakeActor.MapRouteArgsForCall(0) + actualRouteGUID, actualAppGUID, actualAppProtocol := fakeActor.MapRouteArgsForCall(0) Expect(actualRouteGUID).To(Equal("route-guid")) Expect(actualAppGUID).To(Equal("app-guid")) - Expect(actualDestinationProtocol).To(Equal("http2")) + Expect(actualAppProtocol).To(Equal("http2")) }) }) }) @@ -534,10 +534,10 @@ var _ = Describe("map-route Command", func() { Expect(actualPort).To(Equal(cmd.Port)) Expect(fakeActor.MapRouteCallCount()).To(Equal(1)) - actualRouteGUID, actualAppGUID, actualDestinationProtocol := fakeActor.MapRouteArgsForCall(0) + actualRouteGUID, actualAppGUID, actualAppProtocol := fakeActor.MapRouteArgsForCall(0) Expect(actualRouteGUID).To(Equal("route-guid")) Expect(actualAppGUID).To(Equal("app-guid")) - Expect(actualDestinationProtocol).To(Equal("http2")) + Expect(actualAppProtocol).To(Equal("http2")) }) }) @@ -573,10 +573,10 @@ var _ = Describe("map-route Command", func() { Expect(actualPort).To(Equal(cmd.Port)) Expect(fakeActor.MapRouteCallCount()).To(Equal(1)) - actualRouteGUID, actualAppGUID, actualDestinationProtocol := fakeActor.MapRouteArgsForCall(0) + actualRouteGUID, actualAppGUID, actualAppProtocol := fakeActor.MapRouteArgsForCall(0) Expect(actualRouteGUID).To(Equal("route-guid")) Expect(actualAppGUID).To(Equal("app-guid")) - Expect(actualDestinationProtocol).To(Equal("http2")) + Expect(actualAppProtocol).To(Equal("http2")) }) }) }) diff --git a/integration/v7/isolated/map_route_command_test.go b/integration/v7/isolated/map_route_command_test.go index ea734b65fb9..3aaec9b04e5 100644 --- a/integration/v7/isolated/map_route_command_test.go +++ b/integration/v7/isolated/map_route_command_test.go @@ -29,7 +29,7 @@ var _ = Describe("map-route command", func() { Eventually(session).Should(Say(`USAGE:`)) Eventually(session).Should(Say(`Map an HTTP route:\n`)) - Eventually(session).Should(Say(`cf map-route APP_NAME DOMAIN \[--hostname HOSTNAME\] \[--path PATH\] \[--destination-protocol PROTOCOL\]\n`)) + Eventually(session).Should(Say(`cf map-route APP_NAME DOMAIN \[--hostname HOSTNAME\] \[--path PATH\] \[--app-protocol PROTOCOL\]\n`)) Eventually(session).Should(Say(`Map a TCP route:\n`)) Eventually(session).Should(Say(`cf map-route APP_NAME DOMAIN \[--port PORT]\n`)) Eventually(session).Should(Say(`\n`)) @@ -38,7 +38,7 @@ var _ = Describe("map-route command", func() { Eventually(session).Should(Say(`cf map-route my-app example.com # example.com`)) Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost # myhost.example.com`)) Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost --path foo # myhost.example.com/foo`)) - Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost --destination-protocol http2 # myhost.example.com`)) + Eventually(session).Should(Say(`cf map-route my-app example.com --hostname myhost --app-protocol http2 # myhost.example.com`)) Eventually(session).Should(Say(`cf map-route my-app example.com --port 5000 # example.com:5000`)) Eventually(session).Should(Say(`\n`)) @@ -46,7 +46,7 @@ var _ = Describe("map-route command", func() { Eventually(session).Should(Say(`--hostname, -n\s+Hostname for the HTTP route \(required for shared domains\)`)) Eventually(session).Should(Say(`--path\s+Path for the HTTP route`)) Eventually(session).Should(Say(`--port\s+Port for the TCP route \(default: random port\)`)) - Eventually(session).Should(Say(`--destination-protocol\s+\[Beta flag, subject to change\] Protocol for the route destination \(default: http1\). Only applied to HTTP routes`)) + Eventually(session).Should(Say(`--app-protocol\s+\[Beta flag, subject to change\] Protocol for the route destination \(default: http1\). Only applied to HTTP routes`)) Eventually(session).Should(Say(`\n`)) @@ -133,7 +133,7 @@ var _ = Describe("map-route command", func() { }) It("maps the route to an app", func() { - session := helpers.CF("map-route", appName, domainName, "--hostname", route.Host, "--destination-protocol", "http2") + session := helpers.CF("map-route", appName, domainName, "--hostname", route.Host, "--app-protocol", "http2") Eventually(session).Should(Say(`Mapping route %s.%s to app %s with protocol http2 in org %s / space %s as %s\.\.\.`, hostName, domainName, appName, orgName, spaceName, userName)) Eventually(session).Should(Say(`OK`)) @@ -227,7 +227,7 @@ var _ = Describe("map-route command", func() { }) It("maps the route to an app", func() { - session := helpers.CF("map-route", appName, domainName, "--hostname", hostName, "--destination-protocol", "http2") + session := helpers.CF("map-route", appName, domainName, "--hostname", hostName, "--app-protocol", "http2") Eventually(session).Should(Say(`Creating route %s.%s for org %s / space %s as %s\.\.\.`, hostName, domainName, orgName, spaceName, userName)) Eventually(session).Should(Say(`OK`)) Eventually(session).Should(Say(`Mapping route %s.%s to app %s with protocol http2 in org %s / space %s as %s\.\.\.`, hostName, domainName, appName, orgName, spaceName, userName)) From e4464305d99ee67765b58f5c3642883965bdfe64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Diego=20Gonz=C3=A1lez?= <25335192+jdgonzaleza@users.noreply.github.com> Date: Mon, 22 Nov 2021 17:30:51 -0500 Subject: [PATCH 016/248] [Feature] Add app-protocol to cf routes command output (#2234) Currently we do not show the app-protocol in the output of the cf routes command, so a new column must be added to the output. Also, the apps mapped to the route should be displayed in the apps column and must be separated with commas. Co-authored-by: Hector Calderon --- actor/v7action/route.go | 13 +++ actor/v7action/route_test.go | 20 ++++- command/v7/routes_command.go | 2 + command/v7/routes_command_test.go | 29 +++++-- integration/helpers/version.go | 6 +- .../v7/isolated/routes_command_test.go | 85 +++++++++++++++---- 6 files changed, 126 insertions(+), 29 deletions(-) diff --git a/actor/v7action/route.go b/actor/v7action/route.go index 14bde2bf456..d59c318c61f 100644 --- a/actor/v7action/route.go +++ b/actor/v7action/route.go @@ -20,6 +20,7 @@ import ( type RouteSummary struct { resources.Route AppNames []string + AppProtocols []string DomainName string SpaceName string ServiceInstanceName string @@ -275,13 +276,25 @@ func (actor Actor) GetRouteSummaries(routes []resources.Route) ([]RouteSummary, for _, route := range routes { var appNames []string + protocolSet := map[string]bool{} for _, destination := range route.Destinations { appNames = append(appNames, appNamesByGUID[destination.App.GUID]) + protocolSet[destination.Protocol] = true + } + + var appProtocols []string + if len(protocolSet) > 0 { + appProtocols = make([]string, 0, len(protocolSet)) + for key := range protocolSet { + appProtocols = append(appProtocols, key) + } + sort.Strings(appProtocols) } routeSummaries = append(routeSummaries, RouteSummary{ Route: route, AppNames: appNames, + AppProtocols: appProtocols, SpaceName: spaceNamesByGUID[route.SpaceGUID], DomainName: getDomainName(route.URL, route.Host, route.Path, route.Port), ServiceInstanceName: serviceInstanceNameByRouteGUID[route.GUID], diff --git a/actor/v7action/route_test.go b/actor/v7action/route_test.go index 01eafeca46a..064b1863761 100644 --- a/actor/v7action/route_test.go +++ b/actor/v7action/route_test.go @@ -677,6 +677,7 @@ var _ = Describe("Route Actions", func() { App: resources.RouteDestinationApp{ GUID: "app-guid-1", }, + Protocol: "http1", }, }, SpaceGUID: "fake-space-1-guid", @@ -692,11 +693,13 @@ var _ = Describe("Route Actions", func() { App: resources.RouteDestinationApp{ GUID: "app-guid-1", }, + Protocol: "http2", }, { App: resources.RouteDestinationApp{ GUID: "app-guid-2", }, + Protocol: "http1", }, }, SpaceGUID: "fake-space-1-guid", @@ -797,7 +800,8 @@ var _ = Describe("Route Actions", func() { GUID: "route-guid-1", Destinations: []resources.RouteDestination{ { - App: resources.RouteDestinationApp{GUID: "app-guid-1"}, + App: resources.RouteDestinationApp{GUID: "app-guid-1"}, + Protocol: "http1", }, }, SpaceGUID: "fake-space-1-guid", @@ -807,6 +811,7 @@ var _ = Describe("Route Actions", func() { Port: 1, }, AppNames: []string{"app-name-1"}, + AppProtocols: []string{"http1"}, DomainName: "fake-url-1/fake-path-1", SpaceName: "fake-space-1", ServiceInstanceName: "foo", @@ -816,10 +821,12 @@ var _ = Describe("Route Actions", func() { GUID: "route-guid-2", Destinations: []resources.RouteDestination{ { - App: resources.RouteDestinationApp{GUID: "app-guid-1"}, + App: resources.RouteDestinationApp{GUID: "app-guid-1"}, + Protocol: "http2", }, { - App: resources.RouteDestinationApp{GUID: "app-guid-2"}, + App: resources.RouteDestinationApp{GUID: "app-guid-2"}, + Protocol: "http1", }, }, SpaceGUID: "fake-space-1-guid", @@ -829,6 +836,7 @@ var _ = Describe("Route Actions", func() { Port: 2, }, AppNames: []string{"app-name-1", "app-name-2"}, + AppProtocols: []string{"http1", "http2"}, DomainName: "fake-url-2/fake-path-2", SpaceName: "fake-space-1", ServiceInstanceName: "bar", @@ -928,6 +936,10 @@ var _ = Describe("Route Actions", func() { for i := 0; i < batcher.BatchSize*batches; i++ { port := i + 1000 + appProtocol := "http1" + if i%2 == 0 { + appProtocol = "http2" + } route := resources.Route{ GUID: fmt.Sprintf("route-guid-%d", i), Destinations: []resources.RouteDestination{ @@ -935,6 +947,7 @@ var _ = Describe("Route Actions", func() { App: resources.RouteDestinationApp{ GUID: fmt.Sprintf("fake-app-guid-%d", i), }, + Protocol: appProtocol, }, }, SpaceGUID: fmt.Sprintf("fake-space-guid-%d", i), @@ -968,6 +981,7 @@ var _ = Describe("Route Actions", func() { manyResults = append(manyResults, RouteSummary{ Route: route, + AppProtocols: []string{appProtocol}, AppNames: []string{fmt.Sprintf("fake-app-name-%d", i)}, DomainName: fmt.Sprintf("fake-url-%d/fake-path-%d", i, i), SpaceName: fmt.Sprintf("fake-space-name-%d", i), diff --git a/command/v7/routes_command.go b/command/v7/routes_command.go index 4edbd263f12..437704cdc8f 100644 --- a/command/v7/routes_command.go +++ b/command/v7/routes_command.go @@ -82,6 +82,7 @@ func (cmd RoutesCommand) displayRoutesTable(routeSummaries []v7action.RouteSumma cmd.UI.TranslateText("port"), cmd.UI.TranslateText("path"), cmd.UI.TranslateText("protocol"), + cmd.UI.TranslateText("app-protocol"), cmd.UI.TranslateText("apps"), cmd.UI.TranslateText("service instance"), }, @@ -99,6 +100,7 @@ func (cmd RoutesCommand) displayRoutesTable(routeSummaries []v7action.RouteSumma port, routeSummary.Path, routeSummary.Protocol, + strings.Join(routeSummary.AppProtocols, ", "), strings.Join(routeSummary.AppNames, ", "), routeSummary.ServiceInstanceName, }) diff --git a/command/v7/routes_command_test.go b/command/v7/routes_command_test.go index e1bcceacfe8..bc43f357733 100644 --- a/command/v7/routes_command_test.go +++ b/command/v7/routes_command_test.go @@ -29,7 +29,7 @@ var _ = Describe("routes Command", func() { binaryName string ) - const tableHeaders = `space\s+host\s+domain\s+port\s+path\s+protocol\s+apps\s+service instance` + const tableHeaders = `space\s+host\s+domain\s+port\s+path\s+protocol\s+app-protocol\s+apps\s+service instance` BeforeEach(func() { testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) @@ -144,10 +144,16 @@ var _ = Describe("routes Command", func() { Route: resources.Route{GUID: "route-guid-2", Host: "host-3", Path: "/path/2"}, }, { - DomainName: "domain3", - SpaceName: "space-3", - Route: resources.Route{GUID: "route-guid-3", Host: "host-1"}, + DomainName: "domain3", + SpaceName: "space-3", + Route: resources.Route{GUID: "route-guid-3", Host: "host-1", + Destinations: []resources.RouteDestination{ + {GUID: "app1-guid", Protocol: "http1"}, + {GUID: "app2-guid", Protocol: "http2"}, + }, + }, AppNames: []string{"app1", "app2"}, + AppProtocols: []string{"http1", "http2"}, ServiceInstanceName: "si-3", }, { @@ -156,6 +162,18 @@ var _ = Describe("routes Command", func() { Route: resources.Route{GUID: "route-guid-3", Port: 1024}, AppNames: []string{"app1", "app2"}, }, + { + DomainName: "domain4", + SpaceName: "space-3", + Route: resources.Route{GUID: "route-guid-3", Port: 1024, + Destinations: []resources.RouteDestination{ + {GUID: "app1-guid", Protocol: "http1"}, + {GUID: "app2-guid", Protocol: "http1"}, + }, + }, + AppNames: []string{"app1", "app2"}, + AppProtocols: []string{"http1"}, + }, } fakeActor.GetRouteSummariesReturns( @@ -174,8 +192,9 @@ var _ = Describe("routes Command", func() { Expect(testUI.Out).To(Say(tableHeaders)) Expect(testUI.Out).To(Say(`space-1\s+domain1\s+si-1\s+`)) Expect(testUI.Out).To(Say(`space-2\s+host-3\s+domain2\s+\/path\/2`)) - Expect(testUI.Out).To(Say(`space-3\s+host-1\s+domain3\s+app1, app2\s+si-3`)) + Expect(testUI.Out).To(Say(`space-3\s+host-1\s+domain3\s+http1, http2\s+app1, app2\s+si-3`)) Expect(testUI.Out).To(Say(`space-3\s+tcp\.domain\s+1024\s+app1, app2`)) + Expect(testUI.Out).To(Say(`space-3\s+domain4\s+1024\s+http1\s+app1, app2`)) }) }) diff --git a/integration/helpers/version.go b/integration/helpers/version.go index 57297bec1aa..bf9dd585711 100644 --- a/integration/helpers/version.go +++ b/integration/helpers/version.go @@ -87,11 +87,11 @@ func SkipIfUAAVersionAtLeast(version string) { } func matchMajorAPIVersion(minVersion string) string { - version := GetAPIVersionV2() if strings.HasPrefix(minVersion, "3") { - version = getAPIVersionV3() + return getAPIVersionV3() + } else { + return GetAPIVersionV2() } - return version } // GetAPIVersionV2 returns the V2 api version of the targeted API diff --git a/integration/v7/isolated/routes_command_test.go b/integration/v7/isolated/routes_command_test.go index fc2e70450c0..73813867368 100644 --- a/integration/v7/isolated/routes_command_test.go +++ b/integration/v7/isolated/routes_command_test.go @@ -1,6 +1,9 @@ package isolated import ( + "fmt" + + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" . "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers" "code.cloudfoundry.org/cli/integration/helpers" @@ -11,6 +14,9 @@ import ( ) var _ = Describe("routes command", func() { + + appProtocolValue := "http1" + const tableHeaders = `space\s+host\s+domain\s+port\s+path\s+protocol\s+app-protocol\s+apps\s+service instance` Context("Help", func() { It("appears in cf help -a", func() { session := helpers.CF("help", "-a") @@ -60,6 +66,10 @@ var _ = Describe("routes command", func() { helpers.SetupCF(orgName, spaceName) userName, _ = helpers.GetCredentials() + if !helpers.IsVersionMet(ccversion.MinVersionHTTP2RoutingV3) { + appProtocolValue = "" + } + }) AfterEach(func() { @@ -110,38 +120,77 @@ var _ = Describe("routes command", func() { It("lists all the routes", func() { session := helpers.CF("routes") Eventually(session).Should(Exit(0)) - Expect(session).To(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) - Expect(session).To(Say(`space\s+host\s+domain\s+port\s+path\s+protocol\s+apps\s+service instance\n`)) - Expect(session).To(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\n`, spaceName, domainName, appName1, serviceInstanceName)) - Expect(session).To(Say(`%s\s+route1a\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName1)) - Expect(session).To(Say(`%s\s+route1b\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName1)) - Expect(session).ToNot(Say(`%s\s+route2\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName2)) + Expect(session).To(Say(tableHeaders)) + Expect(session).To(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\s+%s\n`, spaceName, domainName, appProtocolValue, appName1, serviceInstanceName)) + Expect(session).To(Say(`%s\s+route1a\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName1)) + Expect(session).To(Say(`%s\s+route1b\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName1)) + Expect(session).ToNot(Say(`%s\s+route2\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName2)) }) It("lists all the routes by label", func() { session := helpers.CF("routes", "--labels", "env in (prod)") Eventually(session).Should(Exit(0)) Expect(session).To(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) - Expect(session).To(Say(`space\s+host\s+domain\s+port\s+path\s+protocol\s+apps\s+service instance\n`)) - Expect(session).ToNot(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\n`, spaceName, domainName, appName1, serviceInstanceName)) - Expect(session).ToNot(Say(`%s\s+route1a\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName1)) - Expect(session).To(Say(`%s\s+route1b\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName1)) - Expect(session).ToNot(Say(`%s\s+route2\s+%s\s+http\s+%s\s+\n`, spaceName, domainName, appName2)) + Expect(session).To(Say(tableHeaders)) + Expect(session).ToNot(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\s+%s\n`, spaceName, domainName, appProtocolValue, appName1, serviceInstanceName)) + Expect(session).ToNot(Say(`%s\s+route1a\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName1)) + Expect(session).To(Say(`%s\s+route1b\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName1)) + Expect(session).ToNot(Say(`%s\s+route2\s+%s\s+http\s+%s\s+%s\s+\n`, spaceName, domainName, appProtocolValue, appName2)) }) When("fetching routes by org", func() { It("lists all the routes in the org", func() { session := helpers.CF("routes", "--org-level") - Eventually(session).Should(Say(`Getting routes for org %s as %s\.\.\.`, orgName, userName)) - Eventually(session).Should(Say(`space\s+host\s+domain\s+port\s+path\s+protocol\s+apps\s+service instance\n`)) - Eventually(session).Should(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\n`, spaceName, domainName, appName1, serviceInstanceName)) - Eventually(session).Should(Say(`%s\s+route2\s+%s\s+\/dodo\s+http\s+%s\s+\n`, otherSpaceName, domainName, appName2)) Eventually(session).Should(Exit(0)) + Expect(session).To(Say(`Getting routes for org %s as %s\.\.\.`, orgName, userName)) + Expect(session).To(Say(tableHeaders)) + Expect(session).To(Say(`%s\s+route1\s+%s\s+http\s+%s\s+%s\s+%s\n`, spaceName, domainName, appProtocolValue, appName1, serviceInstanceName)) + Expect(session).To(Say(`%s\s+route2\s+%s\s+\/dodo\s+http\s+%s\s+%s\s+\n`, otherSpaceName, domainName, appProtocolValue, appName2)) }) }) }) + When("http1 and http2 routes exist", func() { + var ( + domainName string + domain helpers.Domain + ) + + BeforeEach(func() { + helpers.SkipIfVersionLessThan(ccversion.MinVersionHTTP2RoutingV3) + domainName = helpers.NewDomainName() + + domain = helpers.NewDomain(orgName, domainName) + + appName1 = helpers.NewAppName() + Eventually(helpers.CF("create-app", appName1)).Should(Exit(0)) + appName2 = helpers.NewAppName() + Eventually(helpers.CF("create-app", appName2)).Should(Exit(0)) + + domain.CreatePrivate() + + Eventually(helpers.CF("map-route", appName1, domainName, "--hostname", "route1")).Should(Exit(0)) + Eventually(helpers.CF("map-route", appName2, domainName, "--hostname", "route2")).Should(Exit(0)) + Eventually(helpers.CF("map-route", appName2, domainName, "--hostname", "route1", "--app-protocol", "http2")).Should(Exit(0)) + + helpers.SetupCF(orgName, spaceName) + }) + + AfterEach(func() { + domain.Delete() + }) + + It("lists all the routes", func() { + session := helpers.CF("routes") + Eventually(session).Should(Exit(0)) + Expect(session).To(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) + Expect(session).To(Say(tableHeaders)) + Expect(session).To(Say(`%s\s+route1\s+%s\s+http\s+http1, http2\s+%s\s+\n`, spaceName, domainName, fmt.Sprintf("%s, %s", appName1, appName2))) + Expect(session).To(Say(`%s\s+route2\s+%s\s+http\s+http1\s+%s\s+\n`, spaceName, domainName, appName2)) + }) + }) + When("when shared tcp routes exist", func() { var ( domainName string @@ -174,7 +223,7 @@ var _ = Describe("routes command", func() { Eventually(session).Should(Exit(0)) Expect(session).To(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) - Expect(session).To(Say(`space\s+host\s+domain\s+port\s+path\s+protocol\s+apps`)) + Expect(session).To(Say(tableHeaders)) Expect(session).To(Say(`%s\s+%s[^:]\s+%d\s+tcp`, spaceName, domainName, 1028)) }) }) @@ -182,9 +231,9 @@ var _ = Describe("routes command", func() { When("no routes exist", func() { It("outputs a message about no routes existing", func() { session := helpers.CF("routes") - Eventually(session).Should(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) - Eventually(session).Should(Say("No routes found")) Eventually(session).Should(Exit(0)) + Expect(session).To(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) + Expect(session).To(Say("No routes found")) }) }) }) From fd8fbca64b9333e48c394d6613871c033f9aea3e Mon Sep 17 00:00:00 2001 From: Alexander Berezovsky Date: Wed, 9 Feb 2022 23:34:51 +0000 Subject: [PATCH 017/248] Bump version to 8.2.0 --- BUILD_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD_VERSION b/BUILD_VERSION index 8104cabd36f..fbb9ea12de3 100644 --- a/BUILD_VERSION +++ b/BUILD_VERSION @@ -1 +1 @@ -8.1.0 +8.2.0 From 93c1943a38aaaa5834a04ad73e6511e7387129cc Mon Sep 17 00:00:00 2001 From: Maria Shaldybin Date: Tue, 15 Feb 2022 19:42:03 +0000 Subject: [PATCH 018/248] Update the tip for security groups When users have dynamic ASG's feature enabled they don't need to restart/restage their application for security group updates to take and effect. --- command/v7/bind_running_security_group_command.go | 4 ++-- .../v7/bind_running_security_group_command_test.go | 2 +- command/v7/bind_security_group_command.go | 4 ++-- command/v7/bind_security_group_command_test.go | 10 +++++----- command/v7/bind_staging_security_group_command.go | 4 ++-- .../v7/bind_staging_security_group_command_test.go | 2 +- command/v7/delete_security_group_command.go | 4 ++-- command/v7/unbind_running_group_command_test.go | 2 +- .../v7/unbind_running_security_group_command.go | 4 ++-- command/v7/unbind_security_group.go | 6 +++--- command/v7/unbind_security_group_test.go | 4 ++-- .../v7/unbind_staging_security_group_command.go | 4 ++-- .../unbind_staging_security_group_command_test.go | 2 +- command/v7/update_security_group_command.go | 4 ++-- doc/adr/0007-integration-vs-command-test.md | 4 ++-- .../v7/global/bind_security_group_command_test.go | 14 +++++++------- .../unbind_running_security_group_command_test.go | 6 +++--- .../global/unbind_security_group_command_test.go | 10 +++++----- .../unbind_staging_security_group_command_test.go | 6 +++--- .../global/update_security_group_command_test.go | 4 ++-- .../isolated/delete_security_group_command_test.go | 6 +++--- 21 files changed, 53 insertions(+), 53 deletions(-) diff --git a/command/v7/bind_running_security_group_command.go b/command/v7/bind_running_security_group_command.go index 82aca45eb39..b2fafe89867 100644 --- a/command/v7/bind_running_security_group_command.go +++ b/command/v7/bind_running_security_group_command.go @@ -9,7 +9,7 @@ type BindRunningSecurityGroupCommand struct { BaseCommand SecurityGroup flag.SecurityGroup `positional-args:"yes"` - usage interface{} `usage:"CF_NAME bind-running-security-group SECURITY_GROUP\n\nTIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications."` + usage interface{} `usage:"CF_NAME bind-running-security-group SECURITY_GROUP\n\nTIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications."` relatedCommands interface{} `related_commands:"apps, bind-security-group, bind-staging-security-group, restart, running-security-groups, security-groups"` } @@ -38,7 +38,7 @@ func (cmd BindRunningSecurityGroupCommand) Execute(args []string) error { } cmd.UI.DisplayOK() - cmd.UI.DisplayText("TIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications.") + cmd.UI.DisplayText("TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications.") return nil } diff --git a/command/v7/bind_running_security_group_command_test.go b/command/v7/bind_running_security_group_command_test.go index c993a862412..3f8850e9fb5 100644 --- a/command/v7/bind_running_security_group_command_test.go +++ b/command/v7/bind_running_security_group_command_test.go @@ -104,7 +104,7 @@ var _ = Describe("bind-running-security-group Command", func() { It("signals that the security group is bound and provides a helpful tip", func() { Expect(testUI.Out).To(Say("OK")) - Expect(testUI.Out).To(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Expect(testUI.Out).To(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Expect(testUI.Err).To(Say("globally bind security group warning")) Expect(executeErr).NotTo(HaveOccurred()) }) diff --git a/command/v7/bind_security_group_command.go b/command/v7/bind_security_group_command.go index 712eedfd7ca..4350d966eb0 100644 --- a/command/v7/bind_security_group_command.go +++ b/command/v7/bind_security_group_command.go @@ -15,7 +15,7 @@ type BindSecurityGroupCommand struct { RequiredArgs flag.BindSecurityGroupV7Args `positional-args:"yes"` Lifecycle flag.SecurityGroupLifecycle `long:"lifecycle" choice:"running" choice:"staging" default:"running" description:"Lifecycle phase the group applies to."` Space string `long:"space" description:"Space to bind the security group to. (Default: all existing spaces in org)"` - usage interface{} `usage:"CF_NAME bind-security-group SECURITY_GROUP ORG [--lifecycle (running | staging)] [--space SPACE]\n\nTIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications."` + usage interface{} `usage:"CF_NAME bind-security-group SECURITY_GROUP ORG [--lifecycle (running | staging)] [--space SPACE]\n\nTIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications."` relatedCommands interface{} `related_commands:"apps, bind-running-security-group, bind-staging-security-group, restart, security-groups"` } @@ -99,7 +99,7 @@ func (cmd BindSecurityGroupCommand) Execute(args []string) error { cmd.UI.DisplayOK() - cmd.UI.DisplayText("TIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications.") + cmd.UI.DisplayText("TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications.") } return nil diff --git a/command/v7/bind_security_group_command_test.go b/command/v7/bind_security_group_command_test.go index b90fa78d797..17175730fbc 100644 --- a/command/v7/bind_security_group_command_test.go +++ b/command/v7/bind_security_group_command_test.go @@ -211,7 +211,7 @@ var _ = Describe("bind-security-group Command", func() { // When space is provided, Assigning statement should only be printed once Expect(testUI.Out).NotTo(Say(`Assigning running security group some-security-group to space some-space in org some-org as some-user\.\.\.`)) Expect(testUI.Out).To(Say("OK")) - Expect(testUI.Out).To(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Expect(testUI.Out).To(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Expect(testUI.Err).To(Say("get security group warning")) Expect(testUI.Err).To(Say("get org warning")) @@ -276,7 +276,7 @@ var _ = Describe("bind-security-group Command", func() { Expect(testUI.Out).To(Say("Assigning running security group %s to all spaces in org %s as some-user...", cmd.RequiredArgs.SecurityGroupName, cmd.RequiredArgs.OrganizationName)) Expect(testUI.Out).To(Say("No spaces in org %s.", cmd.RequiredArgs.OrganizationName)) Expect(testUI.Out).NotTo(Say("OK")) - Expect(testUI.Out).NotTo(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) //TODO Why? + Expect(testUI.Out).NotTo(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) //TODO Why? Expect(testUI.Err).To(Say("get security group warning")) Expect(testUI.Err).To(Say("get org warning")) @@ -313,7 +313,7 @@ var _ = Describe("bind-security-group Command", func() { Expect(testUI.Out).To(Say(`Assigning running security group some-security-group to spaces some-space-1, some-space-2 in org some-org as some-user\.\.\.`)) Expect(testUI.Out).To(Say("OK")) - Expect(testUI.Out).To(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Expect(testUI.Out).To(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Expect(testUI.Err).To(Say("get security group warning")) Expect(testUI.Err).To(Say("get org warning")) @@ -410,7 +410,7 @@ var _ = Describe("bind-security-group Command", func() { Expect(testUI.Out).To(Say(`Assigning staging security group some-security-group to space some-space in org some-org as some-user\.\.\.`)) Expect(testUI.Out).To(Say("OK")) - Expect(testUI.Out).To(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Expect(testUI.Out).To(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Expect(testUI.Err).To(Say("get security group warning")) Expect(testUI.Err).To(Say("get org warning")) @@ -484,7 +484,7 @@ var _ = Describe("bind-security-group Command", func() { Expect(testUI.Out).To(Say(`Assigning staging security group some-security-group to spaces some-space-1, some-space-2 in org some-org as some-user\.\.\.`)) Expect(testUI.Out).To(Say("OK")) - Expect(testUI.Out).To(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Expect(testUI.Out).To(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Expect(testUI.Err).To(Say("get security group warning")) Expect(testUI.Err).To(Say("get org warning")) diff --git a/command/v7/bind_staging_security_group_command.go b/command/v7/bind_staging_security_group_command.go index 306c0548d0c..0ee5a324052 100644 --- a/command/v7/bind_staging_security_group_command.go +++ b/command/v7/bind_staging_security_group_command.go @@ -9,7 +9,7 @@ type BindStagingSecurityGroupCommand struct { BaseCommand SecurityGroup flag.SecurityGroup `positional-args:"yes"` - usage interface{} `usage:"CF_NAME bind-staging-security-group SECURITY_GROUP\n\nTIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications."` + usage interface{} `usage:"CF_NAME bind-staging-security-group SECURITY_GROUP\n\nTIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications."` relatedCommands interface{} `related_commands:"apps, bind-running-security-group, bind-security-group, restart, security-groups, staging-security-groups"` } @@ -38,7 +38,7 @@ func (cmd BindStagingSecurityGroupCommand) Execute(args []string) error { } cmd.UI.DisplayOK() - cmd.UI.DisplayText("TIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications.") + cmd.UI.DisplayText("TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications.") return nil } diff --git a/command/v7/bind_staging_security_group_command_test.go b/command/v7/bind_staging_security_group_command_test.go index c7069f91b7a..634ee60352a 100644 --- a/command/v7/bind_staging_security_group_command_test.go +++ b/command/v7/bind_staging_security_group_command_test.go @@ -104,7 +104,7 @@ var _ = Describe("bind-staging-security-group Command", func() { It("signals that the security group is bound and provides a helpful tip", func() { Expect(testUI.Out).To(Say("OK")) - Expect(testUI.Out).To(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Expect(testUI.Out).To(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Expect(testUI.Err).To(Say("globally bind security group warning")) Expect(executeErr).NotTo(HaveOccurred()) }) diff --git a/command/v7/delete_security_group_command.go b/command/v7/delete_security_group_command.go index cc446096cbf..6a941bcd45f 100644 --- a/command/v7/delete_security_group_command.go +++ b/command/v7/delete_security_group_command.go @@ -10,7 +10,7 @@ type DeleteSecurityGroupCommand struct { RequiredArgs flag.SecurityGroup `positional-args:"yes"` Force bool `long:"force" short:"f" description:"Force deletion without confirmation"` - usage interface{} `usage:"CF_NAME delete-security-group SECURITY_GROUP [-f]\n\nTIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications."` + usage interface{} `usage:"CF_NAME delete-security-group SECURITY_GROUP [-f]\n\nTIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications."` relatedCommands interface{} `related_commands:"security-groups"` } @@ -64,7 +64,7 @@ func (cmd *DeleteSecurityGroupCommand) Execute(args []string) error { cmd.UI.DisplayOK() cmd.UI.DisplayNewline() - cmd.UI.DisplayText("TIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications.") + cmd.UI.DisplayText("TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications.") return nil } diff --git a/command/v7/unbind_running_group_command_test.go b/command/v7/unbind_running_group_command_test.go index cef38fad9c6..a02066ab052 100644 --- a/command/v7/unbind_running_group_command_test.go +++ b/command/v7/unbind_running_group_command_test.go @@ -66,7 +66,7 @@ var _ = Describe("unbind-running-security-group Command", func() { Expect(executeErr).NotTo(HaveOccurred()) Expect(testUI.Out).To(Say("Unbinding security group %s from defaults for running as some-user...", cmd.RequiredArgs.SecurityGroup)) Expect(testUI.Out).To(Say("OK")) - Expect(testUI.Out).To(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Expect(testUI.Out).To(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Expect(testUI.Err).To(Say("get security group warning")) }) diff --git a/command/v7/unbind_running_security_group_command.go b/command/v7/unbind_running_security_group_command.go index 264a4ab86cd..fd5ac730f39 100644 --- a/command/v7/unbind_running_security_group_command.go +++ b/command/v7/unbind_running_security_group_command.go @@ -10,7 +10,7 @@ type UnbindRunningSecurityGroupCommand struct { BaseCommand RequiredArgs flag.SecurityGroup `positional-args:"yes"` - usage interface{} `usage:"CF_NAME unbind-running-security-group SECURITY_GROUP\n\nTIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications."` + usage interface{} `usage:"CF_NAME unbind-running-security-group SECURITY_GROUP\n\nTIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications."` relatedCommands interface{} `related_commands:"apps, restart, running-security-groups, security-groups"` } @@ -45,7 +45,7 @@ func (cmd UnbindRunningSecurityGroupCommand) Execute(args []string) error { } cmd.UI.DisplayOK() - cmd.UI.DisplayText("TIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications.") + cmd.UI.DisplayText("TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications.") return nil } diff --git a/command/v7/unbind_security_group.go b/command/v7/unbind_security_group.go index 9bc55399cc8..e4a6b00f153 100644 --- a/command/v7/unbind_security_group.go +++ b/command/v7/unbind_security_group.go @@ -12,7 +12,7 @@ type UnbindSecurityGroupCommand struct { RequiredArgs flag.UnbindSecurityGroupV7Args `positional-args:"yes"` Lifecycle flag.SecurityGroupLifecycle `long:"lifecycle" choice:"running" choice:"staging" default:"running" description:"Lifecycle phase the group applies to"` - usage interface{} `usage:"CF_NAME unbind-security-group SECURITY_GROUP ORG SPACE [--lifecycle (running | staging)]\n\nTIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications."` + usage interface{} `usage:"CF_NAME unbind-security-group SECURITY_GROUP ORG SPACE [--lifecycle (running | staging)]\n\nTIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications."` relatedCommands interface{} `related_commands:"apps, restart, security-groups"` } @@ -52,7 +52,7 @@ func (cmd UnbindSecurityGroupCommand) Execute(args []string) error { cmd.UI.DisplayWarning(err.Error()) cmd.UI.DisplayOK() - cmd.UI.DisplayText("TIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications.") + cmd.UI.DisplayText("TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications.") return nil } @@ -60,7 +60,7 @@ func (cmd UnbindSecurityGroupCommand) Execute(args []string) error { } cmd.UI.DisplayOK() - cmd.UI.DisplayText("TIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications.") + cmd.UI.DisplayText("TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications.") return nil } diff --git a/command/v7/unbind_security_group_test.go b/command/v7/unbind_security_group_test.go index 4af1a6edb30..cfeac315ed0 100644 --- a/command/v7/unbind_security_group_test.go +++ b/command/v7/unbind_security_group_test.go @@ -126,7 +126,7 @@ var _ = Describe("unbind-security-group Command", func() { Expect(lifecycle).To(Equal(constant.SecurityGroupLifecycle("some-lifecycle"))) Expect(testUI.Err).To(Say("Security group some-security-group not bound to space some-space for lifecycle phase 'some-lifecycle'.")) Expect(testUI.Out).To(Say("OK\n\n")) - Expect(testUI.Out).To(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Expect(testUI.Out).To(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Expect(executeErr).NotTo(HaveOccurred()) }) }) @@ -143,7 +143,7 @@ var _ = Describe("unbind-security-group Command", func() { It("indicates it successfully unbound the security group", func() { Expect(testUI.Out).To(Say("OK\n\n")) - Expect(testUI.Out).To(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Expect(testUI.Out).To(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) }) }) diff --git a/command/v7/unbind_staging_security_group_command.go b/command/v7/unbind_staging_security_group_command.go index 3734ed62483..a82f1541f28 100644 --- a/command/v7/unbind_staging_security_group_command.go +++ b/command/v7/unbind_staging_security_group_command.go @@ -10,7 +10,7 @@ type UnbindStagingSecurityGroupCommand struct { BaseCommand RequiredArgs flag.SecurityGroup `positional-args:"yes"` - usage interface{} `usage:"CF_NAME unbind-staging-security-group SECURITY_GROUP\n\nTIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications."` + usage interface{} `usage:"CF_NAME unbind-staging-security-group SECURITY_GROUP\n\nTIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications."` relatedCommands interface{} `related_commands:"apps, restart, security-groups, staging-security-groups"` } @@ -45,7 +45,7 @@ func (cmd UnbindStagingSecurityGroupCommand) Execute(args []string) error { } cmd.UI.DisplayOK() - cmd.UI.DisplayText("TIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications.") + cmd.UI.DisplayText("TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications.") return nil } diff --git a/command/v7/unbind_staging_security_group_command_test.go b/command/v7/unbind_staging_security_group_command_test.go index 7588628cc73..4658d8ed3ab 100644 --- a/command/v7/unbind_staging_security_group_command_test.go +++ b/command/v7/unbind_staging_security_group_command_test.go @@ -66,7 +66,7 @@ var _ = Describe("unbind-staging-security-group Command", func() { Expect(executeErr).NotTo(HaveOccurred()) Expect(testUI.Out).To(Say("Unbinding security group %s from defaults for staging as some-user...", cmd.RequiredArgs.SecurityGroup)) Expect(testUI.Out).To(Say("OK")) - Expect(testUI.Out).To(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Expect(testUI.Out).To(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Expect(testUI.Err).To(Say("get security group warning")) }) diff --git a/command/v7/update_security_group_command.go b/command/v7/update_security_group_command.go index 6fdbbd3f6e2..b24f47af389 100644 --- a/command/v7/update_security_group_command.go +++ b/command/v7/update_security_group_command.go @@ -11,7 +11,7 @@ type UpdateSecurityGroupCommand struct { BaseCommand RequiredArgs flag.SecurityGroupArgs `positional-args:"yes"` - usage interface{} `usage:"CF_NAME update-security-group SECURITY_GROUP PATH_TO_JSON_RULES_FILE\n\n The provided path can be an absolute or relative path to a file. The file should have\n a single array with JSON objects inside describing the rules. The JSON Base Object is\n omitted and only the square brackets and associated child object are required in the file.\n\n Valid json file example:\n [\n {\n \"protocol\": \"tcp\",\n \"destination\": \"10.0.11.0/24\",\n \"ports\": \"80,443\",\n \"description\": \"Allow http and https traffic from ZoneA\"\n }\n ]\n\nTIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications."` + usage interface{} `usage:"CF_NAME update-security-group SECURITY_GROUP PATH_TO_JSON_RULES_FILE\n\n The provided path can be an absolute or relative path to a file. The file should have\n a single array with JSON objects inside describing the rules. The JSON Base Object is\n omitted and only the square brackets and associated child object are required in the file.\n\n Valid json file example:\n [\n {\n \"protocol\": \"tcp\",\n \"destination\": \"10.0.11.0/24\",\n \"ports\": \"80,443\",\n \"description\": \"Allow http and https traffic from ZoneA\"\n }\n ]\n\nTIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications."` relatedCommands interface{} `related_commands:"restage, security-groups"` } @@ -44,6 +44,6 @@ func (cmd UpdateSecurityGroupCommand) Execute(args []string) error { cmd.UI.DisplayOK() cmd.UI.DisplayNewline() - cmd.UI.DisplayText("TIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications.") + cmd.UI.DisplayText("TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications.") return nil } diff --git a/doc/adr/0007-integration-vs-command-test.md b/doc/adr/0007-integration-vs-command-test.md index 620b2589f70..8d7a721741d 100644 --- a/doc/adr/0007-integration-vs-command-test.md +++ b/doc/adr/0007-integration-vs-command-test.md @@ -38,7 +38,7 @@ output/functionality: > Security group my-group not bound to space my-space for lifecycle phase 'running'. > OK > -> TIP: Changes require an app restart (for running) or restage (for staging) to apply to existing applications. +> TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart (for running) or restage (for staging) to apply to existing applications. > ``` To do so, we would have to make a `BeforeEach()` that creates the scenario @@ -62,7 +62,7 @@ When("the space isn't bound to the security group in any lifecycle", func() { Eventually(session).Should(Say(`Unbinding security group %s from org %s / space %s as %s\.\.\.`, securityGroupName, orgName, spaceName, username)) Eventually(session.Err).Should(Say(`Security group %s not bound to space %s for lifecycle phase 'running'\.`, securityGroupName, spaceName)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) }) }) diff --git a/integration/v7/global/bind_security_group_command_test.go b/integration/v7/global/bind_security_group_command_test.go index 10a3a859c81..cc881ecb38a 100644 --- a/integration/v7/global/bind_security_group_command_test.go +++ b/integration/v7/global/bind_security_group_command_test.go @@ -36,7 +36,7 @@ var _ = Describe("bind-security-group command", func() { Eventually(session).Should(Say(`\s+bind-security-group - Bind a security group to a particular space, or all existing spaces of an org`)) Eventually(session).Should(Say("USAGE:")) Eventually(session).Should(Say(`\s+cf bind-security-group SECURITY_GROUP ORG \[--lifecycle \(running \| staging\)\] \[--space SPACE\]`)) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Say("OPTIONS:")) Eventually(session).Should(Say(`\s+--lifecycle Lifecycle phase the group applies to\. \(Default: running\)`)) Eventually(session).Should(Say(`\s+--space Space to bind the security group to\. \(Default: all existing spaces in org\)`)) @@ -151,7 +151,7 @@ var _ = Describe("bind-security-group command", func() { Eventually(session).Should(Say("Assigning running security group %s to all spaces in org %s as %s...", secGroupName, orgName, userName)) Eventually(session).Should(Say("No spaces in org %s.", orgName)) Consistently(session).ShouldNot(Say("OK")) - Eventually(session).ShouldNot(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).ShouldNot(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) }) }) @@ -169,7 +169,7 @@ var _ = Describe("bind-security-group command", func() { userName, _ := helpers.GetCredentials() Eventually(session).Should(Say(`Assigning running security group %s to spaces INTEGRATION-SPACE.*, INTEGRATION-SPACE.* in org %s as %s\.\.\.`, secGroupName, orgName, userName)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) }) }) @@ -181,7 +181,7 @@ var _ = Describe("bind-security-group command", func() { userName, _ := helpers.GetCredentials() Eventually(session).Should(Say(`Assigning running security group %s to space %s in org %s as %s\.\.\.`, secGroupName, spaceName1, orgName, userName)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) }) }) @@ -193,7 +193,7 @@ var _ = Describe("bind-security-group command", func() { userName, _ := helpers.GetCredentials() Eventually(session).Should(Say(`Assigning running security group %s to space %s in org %s as %s\.\.\.`, secGroupName, spaceName1, orgName, userName)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) }) }) @@ -206,7 +206,7 @@ var _ = Describe("bind-security-group command", func() { userName, _ := helpers.GetCredentials() Eventually(session).Should(Say(`Assigning staging security group %s to spaces INTEGRATION-SPACE.*, INTEGRATION-SPACE.* in org %s as %s\.\.\.`, secGroupName, orgName, userName)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) }) }) @@ -217,7 +217,7 @@ var _ = Describe("bind-security-group command", func() { userName, _ := helpers.GetCredentials() Eventually(session).Should(Say(`Assigning staging security group %s to space %s in org %s as %s\.\.\.`, secGroupName, spaceName1, orgName, userName)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) }) }) diff --git a/integration/v7/global/unbind_running_security_group_command_test.go b/integration/v7/global/unbind_running_security_group_command_test.go index 8bcdebb916d..73d3c8c9e17 100644 --- a/integration/v7/global/unbind_running_security_group_command_test.go +++ b/integration/v7/global/unbind_running_security_group_command_test.go @@ -27,7 +27,7 @@ var _ = Describe("unbind-running-security-group command", func() { Eventually(session).Should(Say(`\s+unbind-running-security-group - Unbind a security group from the set of security groups for running applications globally`)) Eventually(session).Should(Say("USAGE:")) Eventually(session).Should(Say(`\s+cf unbind-running-security-group SECURITY_GROUP`)) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Say("SEE ALSO:")) Eventually(session).Should(Say(`\s+apps, restart, running-security-groups, security-groups`)) Eventually(session).Should(Exit(0)) @@ -84,13 +84,13 @@ var _ = Describe("unbind-running-security-group command", func() { userName, _ := helpers.GetCredentials() Eventually(session).Should(Say("Unbinding security group %s from defaults for running as %s...", secGroupName, userName)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) session = helpers.CF("unbind-running-security-group", secGroupName) Eventually(session).Should(Say("Unbinding security group %s from defaults for running as %s...", secGroupName, userName)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) }) }) diff --git a/integration/v7/global/unbind_security_group_command_test.go b/integration/v7/global/unbind_security_group_command_test.go index 5c29ace218f..c42bbdc5152 100644 --- a/integration/v7/global/unbind_security_group_command_test.go +++ b/integration/v7/global/unbind_security_group_command_test.go @@ -31,7 +31,7 @@ var _ = Describe("unbind-security-group command", func() { Eventually(session).Should(Say(`\s+unbind-security-group - Unbind a security group from a space`)) Eventually(session).Should(Say("USAGE:")) Eventually(session).Should(Say(`\s+cf unbind-security-group SECURITY_GROUP ORG SPACE \[--lifecycle \(running \| staging\)\]`)) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Say("OPTIONS:")) Eventually(session).Should(Say(`\s+--lifecycle Lifecycle phase the group applies to \(Default: running\)`)) Eventually(session).Should(Say("SEE ALSO:")) @@ -153,7 +153,7 @@ var _ = Describe("unbind-security-group command", func() { Eventually(session).Should(Say(`Unbinding running security group %s from org %s / space %s as %s\.\.\.`, securityGroupName, orgName, spaceName, username)) Eventually(session.Err).Should(Say(`Security group %s not bound to space %s for lifecycle phase 'running'\.`, securityGroupName, spaceName)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) }) }) @@ -172,7 +172,7 @@ var _ = Describe("unbind-security-group command", func() { session := helpers.CF("unbind-security-group", securityGroupName, orgName, spaceName) Eventually(session).Should(Say(`Unbinding running security group %s from org %s / space %s as %s\.\.\.`, securityGroupName, orgName, spaceName, username)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) }) }) @@ -186,7 +186,7 @@ var _ = Describe("unbind-security-group command", func() { session := helpers.CF("unbind-security-group", securityGroupName, orgName, spaceName, "--lifecycle", "running") Eventually(session).Should(Say(`Unbinding running security group %s from org %s / space %s as %s\.\.\.`, securityGroupName, orgName, spaceName, username)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) }) }) @@ -248,7 +248,7 @@ var _ = Describe("unbind-security-group command", func() { session := helpers.CF("unbind-security-group", securityGroupName, orgName, spaceName, "--lifecycle", "staging") Eventually(session).Should(Say(`Unbinding staging security group %s from org %s / space %s as %s\.\.\.`, securityGroupName, orgName, spaceName, username)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) }) }) diff --git a/integration/v7/global/unbind_staging_security_group_command_test.go b/integration/v7/global/unbind_staging_security_group_command_test.go index d32c232716c..19916d0e063 100644 --- a/integration/v7/global/unbind_staging_security_group_command_test.go +++ b/integration/v7/global/unbind_staging_security_group_command_test.go @@ -27,7 +27,7 @@ var _ = Describe("unbind-staging-security-group command", func() { Eventually(session).Should(Say(`\s+unbind-staging-security-group - Unbind a security group from the set of security groups for staging applications globally`)) Eventually(session).Should(Say("USAGE:")) Eventually(session).Should(Say(`\s+cf unbind-staging-security-group SECURITY_GROUP`)) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Say("SEE ALSO:")) Eventually(session).Should(Say(`\s+apps, restart, security-groups, staging-security-groups`)) Eventually(session).Should(Exit(0)) @@ -84,13 +84,13 @@ var _ = Describe("unbind-staging-security-group command", func() { userName, _ := helpers.GetCredentials() Eventually(session).Should(Say("Unbinding security group %s from defaults for staging as %s...", secGroupName, userName)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) session = helpers.CF("unbind-staging-security-group", secGroupName) Eventually(session).Should(Say("Unbinding security group %s from defaults for staging as %s...", secGroupName, userName)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) }) }) diff --git a/integration/v7/global/update_security_group_command_test.go b/integration/v7/global/update_security_group_command_test.go index 9954cddef82..57c7a9ffb44 100644 --- a/integration/v7/global/update_security_group_command_test.go +++ b/integration/v7/global/update_security_group_command_test.go @@ -78,7 +78,7 @@ var _ = Describe("update-security-group command", func() { session := helpers.CF("update-security-group", securityGroupName, updatedRulesPath) Eventually(session).Should(Say(`Updating security group %s as %s`, securityGroupName, username)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) session = helpers.CF("security-group", securityGroupName) @@ -160,7 +160,7 @@ func displaysUpdateSecurityGroupHelpText(session *Session) { Eventually(session).Should(Say(`"description": "Allow http and https traffic from ZoneA"`)) Eventually(session).Should(Say("}")) Eventually(session).Should(Say("]")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Say("SEE ALSO:")) Eventually(session).Should(Say("restage, security-groups")) } diff --git a/integration/v7/isolated/delete_security_group_command_test.go b/integration/v7/isolated/delete_security_group_command_test.go index cfab73cda10..6cf0746204e 100644 --- a/integration/v7/isolated/delete_security_group_command_test.go +++ b/integration/v7/isolated/delete_security_group_command_test.go @@ -18,7 +18,7 @@ var _ = Describe("delete-security-group command", func() { Eventually(session).Should(Say(`\s+delete-security-group - Deletes a security group`)) Eventually(session).Should(Say("USAGE:")) Eventually(session).Should(Say(`\s+cf delete-security-group SECURITY_GROUP \[-f\]`)) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Say("OPTIONS:")) Eventually(session).Should(Say(`\s+--force, -f\s+Force deletion without confirmation`)) Eventually(session).Should(Say("SEE ALSO:")) @@ -110,7 +110,7 @@ var _ = Describe("delete-security-group command", func() { Eventually(session).Should(Say(`Really delete the security group %s?`, securityGroupName)) Eventually(session).Should(Say("Deleting security group %s as %s", securityGroupName, username)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) Eventually(helpers.CF("security-group", securityGroupName)).Should(Exit(1)) }) @@ -179,7 +179,7 @@ var _ = Describe("delete-security-group command", func() { session := helpers.CF("delete-security-group", securityGroupName, "-f") Eventually(session).Should(Say("Deleting security group %s as %s", securityGroupName, username)) Eventually(session).Should(Say("OK")) - Eventually(session).Should(Say(`TIP: Changes require an app restart \(for running\) or restage \(for staging\) to apply to existing applications.`)) + Eventually(session).Should(Say(`TIP: If Dynamic ASG's are enabled, changes will automatically apply for running and staging applications. Otherwise, changes will require an app restart \(for running\) or restage \(for staging\) to apply to existing applications\.`)) Eventually(session).Should(Exit(0)) Eventually(helpers.CF("security-group", securityGroupName)).Should(Exit(1)) }) From a3668718688b91c1879b90249e09fa4c28ea1d79 Mon Sep 17 00:00:00 2001 From: Shwetha Gururaj Date: Wed, 16 Feb 2022 16:01:41 -0500 Subject: [PATCH 019/248] [Feature] Upgrade Golang version from 1.16 to 1.17 Some high security issues have been solved in the newer versions of go. Moreover, there are some security enhancements coming from 1.17. --- go.mod | 70 +++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 4733b4ee0d6..fd09459e347 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module code.cloudfoundry.org/cli -go 1.16 +go 1.17 require ( code.cloudfoundry.org/bytefmt v0.0.0-20170428003108-f4415fafc561 @@ -16,49 +16,89 @@ require ( code.cloudfoundry.org/lager v1.1.1-0.20191008172124-a9afc05ee5be code.cloudfoundry.org/tlsconfig v0.0.0-20210615191307-5d92ef3894a7 code.cloudfoundry.org/ykk v0.0.0-20170424192843-e4df4ce2fd4d - github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect github.com/SermoDigital/jose v0.9.2-0.20161205224733-f6df55f235c2 github.com/blang/semver v3.5.1+incompatible - github.com/bmatcuk/doublestar v1.3.1 // indirect - github.com/charlievieth/fs v0.0.0-20170613215519-7dc373669fa1 // indirect github.com/cloudfoundry/bosh-cli v5.5.1+incompatible - github.com/cloudfoundry/bosh-utils v0.0.0-20180315210917-c6a922e299b8 // indirect - github.com/cppforlife/go-patch v0.1.0 // indirect github.com/cyphar/filepath-securejoin v0.2.1 github.com/docker/distribution v2.6.0-rc.1.0.20171109224904-e5b5e44386f7+incompatible - github.com/docker/docker v1.4.2-0.20171120205147-9de84a78d76e // indirect github.com/fatih/color v1.5.1-0.20170926111411-5df930a27be2 - github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 github.com/jessevdk/go-flags v1.4.1-0.20181221193153-c0795c8afcf4 github.com/kr/pty v1.1.1 github.com/lunixbochs/vtclean v1.0.0 github.com/mattn/go-colorable v0.1.0 - github.com/mattn/go-isatty v0.0.3 // indirect github.com/mattn/go-runewidth v0.0.5-0.20181218000649-703b5e6b11ae github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2 github.com/moby/moby v1.4.2-0.20171120205147-9de84a78d76e github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d github.com/onsi/ginkgo v1.16.4 github.com/onsi/gomega v1.13.0 - github.com/opencontainers/go-digest v1.0.0-rc1 // indirect github.com/pkg/errors v0.9.1 github.com/sabhiram/go-gitignore v0.0.0-20171017070213-362f9845770f github.com/sajari/fuzzy v1.0.0 github.com/sirupsen/logrus v1.2.0 - github.com/tedsuo/ifrit v0.0.0-20191009134036-9a97d0632f00 // indirect github.com/tedsuo/rata v1.0.1-0.20170830210128-07d200713958 github.com/vito/go-interact v0.0.0-20171111012221-fa338ed9e9ec golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 golang.org/x/net v0.0.0-20211013171255-e13a2654a71e - golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect golang.org/x/text v0.3.7 - golang.org/x/tools v0.1.6-0.20210908190839-cf92b39a962c // indirect - google.golang.org/genproto v0.0.0-20211013025323-ce878158c4d4 // indirect - google.golang.org/grpc v1.41.0 // indirect gopkg.in/cheggaaa/pb.v1 v1.0.28 gopkg.in/yaml.v2 v2.4.0 + k8s.io/apimachinery v0.22.2 k8s.io/client-go v0.22.2 ) +require ( + cloud.google.com/go v0.65.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest v0.11.18 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect + github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/bmatcuk/doublestar v1.3.1 // indirect + github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40 // indirect + github.com/charlievieth/fs v0.0.0-20170613215519-7dc373669fa1 // indirect + github.com/cloudfoundry/bosh-utils v0.0.0-20180315210917-c6a922e299b8 // indirect + github.com/cppforlife/go-patch v0.1.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/docker/docker v1.4.2-0.20171120205147-9de84a78d76e // indirect + github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect + github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/go-logr/logr v0.4.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/go-cmp v0.5.6 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.6.0 // indirect + github.com/imdario/mergo v0.3.5 // indirect + github.com/json-iterator/go v1.1.11 // indirect + github.com/konsorten/go-windows-terminal-sequences v1.0.1 // indirect + github.com/mattn/go-isatty v0.0.3 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/nxadm/tail v1.4.8 // indirect + github.com/opencontainers/go-digest v1.0.0-rc1 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/tedsuo/ifrit v0.0.0-20191009134036-9a97d0632f00 // indirect + golang.org/x/mod v0.4.2 // indirect + golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect + golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect + golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect + golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect + golang.org/x/tools v0.1.6-0.20210908190839-cf92b39a962c // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/appengine v1.6.6 // indirect + google.golang.org/genproto v0.0.0-20211013025323-ce878158c4d4 // indirect + google.golang.org/grpc v1.41.0 // indirect + google.golang.org/protobuf v1.27.1 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + k8s.io/klog/v2 v2.9.0 // indirect + k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect + sigs.k8s.io/yaml v1.2.0 // indirect +) + replace gopkg.in/fsnotify.v1 v1.4.7 => github.com/fsnotify/fsnotify v1.4.7 From 336aa0a09519859a8a245fb0151621937213bfac Mon Sep 17 00:00:00 2001 From: Hector J Calderon Date: Thu, 17 Feb 2022 15:34:06 -0500 Subject: [PATCH 020/248] [Sustaining] Updating go files with linter doing gofmt -l -w . Co-authored-by: Shwetha Gururaj --- actor/pluginaction/install_unix_test.go | 1 + actor/pluginaction/install_windows_test.go | 1 + actor/sharedaction/fix_mode_unix.go | 1 + actor/sharedaction/fix_mode_windows.go | 1 + actor/sharedaction/resource_darwin_test.go | 1 + actor/sharedaction/resource_linux_test.go | 1 + actor/sharedaction/resource_unix_test.go | 1 + actor/v7action/buildpack_unix_test.go | 1 + actor/v7action/buildpack_windows_test.go | 1 + actor/v7action/fix_mode_unix.go | 1 + actor/v7action/fix_mode_windows.go | 1 + cf/cmd/writer_unix.go | 1 + cf/cmd/writer_windows.go | 1 + cf/configuration/config_disk_persistor_unix.go | 1 + cf/configuration/config_disk_persistor_win.go | 1 + cf/net/progress_reader_test.go | 1 + cf/ssh/sigwinch/sigwinch.go | 1 + cf/ssh/sigwinch/sigwinch_win.go | 1 + cf/ssh/ssh_test.go | 1 + cf/terminal/ui_unix.go | 1 + cf/terminal/ui_windows.go | 1 + command/flag/environment_variable_test.go | 1 + integration/helpers/plugin_repo_platform_unix.go | 1 + integration/helpers/plugin_repo_platform_windows.go | 1 + integration/shared/plugin/install_plugin_command_unix_test.go | 1 + integration/shared/plugin/uninstall_plugin_command_unix_test.go | 1 + tools/tools.go | 1 + util/clissh/sigwinch/sigwinch.go | 1 + util/clissh/sigwinch/sigwinch_win.go | 1 + util/clissh/ssh_test.go | 1 + util/configv3/config_unix_test.go | 1 + util/configv3/config_windows_test.go | 1 + util/configv3/home_dir_unix.go | 1 + util/configv3/home_dir_windows.go | 1 + util/generic/executable_filename_unix.go | 1 + util/generic/executable_filename_unix_test.go | 1 + util/generic/executable_filename_windows.go | 1 + util/generic/executable_filename_windows_test.go | 1 + util/manifest/manifest_unix_test.go | 1 + util/manifest/manifest_windows_test.go | 1 + 40 files changed, 40 insertions(+) diff --git a/actor/pluginaction/install_unix_test.go b/actor/pluginaction/install_unix_test.go index 6eb7796dd1b..3c5227c5a65 100644 --- a/actor/pluginaction/install_unix_test.go +++ b/actor/pluginaction/install_unix_test.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package pluginaction_test diff --git a/actor/pluginaction/install_windows_test.go b/actor/pluginaction/install_windows_test.go index 536b61932a1..f1ce037a6fd 100644 --- a/actor/pluginaction/install_windows_test.go +++ b/actor/pluginaction/install_windows_test.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package pluginaction_test diff --git a/actor/sharedaction/fix_mode_unix.go b/actor/sharedaction/fix_mode_unix.go index bbe7e9fc15c..680fe4cf8e8 100644 --- a/actor/sharedaction/fix_mode_unix.go +++ b/actor/sharedaction/fix_mode_unix.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package sharedaction diff --git a/actor/sharedaction/fix_mode_windows.go b/actor/sharedaction/fix_mode_windows.go index 422a0ccb031..2e726c70782 100644 --- a/actor/sharedaction/fix_mode_windows.go +++ b/actor/sharedaction/fix_mode_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package sharedaction diff --git a/actor/sharedaction/resource_darwin_test.go b/actor/sharedaction/resource_darwin_test.go index f9e87be6eab..21444f4d461 100644 --- a/actor/sharedaction/resource_darwin_test.go +++ b/actor/sharedaction/resource_darwin_test.go @@ -1,3 +1,4 @@ +//go:build !windows && !linux // +build !windows,!linux package sharedaction_test diff --git a/actor/sharedaction/resource_linux_test.go b/actor/sharedaction/resource_linux_test.go index bc48769ae34..525a41444f0 100644 --- a/actor/sharedaction/resource_linux_test.go +++ b/actor/sharedaction/resource_linux_test.go @@ -1,3 +1,4 @@ +//go:build !windows && !darwin // +build !windows,!darwin package sharedaction_test diff --git a/actor/sharedaction/resource_unix_test.go b/actor/sharedaction/resource_unix_test.go index cfbcceb112e..4de5d12432b 100644 --- a/actor/sharedaction/resource_unix_test.go +++ b/actor/sharedaction/resource_unix_test.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package sharedaction_test diff --git a/actor/v7action/buildpack_unix_test.go b/actor/v7action/buildpack_unix_test.go index 6ec78dbac64..5df6bd7c727 100644 --- a/actor/v7action/buildpack_unix_test.go +++ b/actor/v7action/buildpack_unix_test.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package v7action_test diff --git a/actor/v7action/buildpack_windows_test.go b/actor/v7action/buildpack_windows_test.go index 8e1218dadb2..eb48786c536 100644 --- a/actor/v7action/buildpack_windows_test.go +++ b/actor/v7action/buildpack_windows_test.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package v7action_test diff --git a/actor/v7action/fix_mode_unix.go b/actor/v7action/fix_mode_unix.go index 69330b77eb9..5a3e9de0821 100644 --- a/actor/v7action/fix_mode_unix.go +++ b/actor/v7action/fix_mode_unix.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package v7action diff --git a/actor/v7action/fix_mode_windows.go b/actor/v7action/fix_mode_windows.go index e6cd6c1256d..2ad56dedc16 100644 --- a/actor/v7action/fix_mode_windows.go +++ b/actor/v7action/fix_mode_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package v7action diff --git a/cf/cmd/writer_unix.go b/cf/cmd/writer_unix.go index bd301a68f5c..c357dbbfa86 100644 --- a/cf/cmd/writer_unix.go +++ b/cf/cmd/writer_unix.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package cmd diff --git a/cf/cmd/writer_windows.go b/cf/cmd/writer_windows.go index 892f350bf92..2d9cab4980e 100644 --- a/cf/cmd/writer_windows.go +++ b/cf/cmd/writer_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package cmd diff --git a/cf/configuration/config_disk_persistor_unix.go b/cf/configuration/config_disk_persistor_unix.go index b1d45200ba0..bdbfb3ddf08 100644 --- a/cf/configuration/config_disk_persistor_unix.go +++ b/cf/configuration/config_disk_persistor_unix.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package configuration diff --git a/cf/configuration/config_disk_persistor_win.go b/cf/configuration/config_disk_persistor_win.go index 859d252a858..663a7689887 100644 --- a/cf/configuration/config_disk_persistor_win.go +++ b/cf/configuration/config_disk_persistor_win.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package configuration diff --git a/cf/net/progress_reader_test.go b/cf/net/progress_reader_test.go index 9e220268991..34e37541ade 100644 --- a/cf/net/progress_reader_test.go +++ b/cf/net/progress_reader_test.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package net_test diff --git a/cf/ssh/sigwinch/sigwinch.go b/cf/ssh/sigwinch/sigwinch.go index ace01f9a2a2..6eab1ee5e72 100644 --- a/cf/ssh/sigwinch/sigwinch.go +++ b/cf/ssh/sigwinch/sigwinch.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package sigwinch diff --git a/cf/ssh/sigwinch/sigwinch_win.go b/cf/ssh/sigwinch/sigwinch_win.go index eac5f1ec141..045da2d6721 100644 --- a/cf/ssh/sigwinch/sigwinch_win.go +++ b/cf/ssh/sigwinch/sigwinch_win.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package sigwinch diff --git a/cf/ssh/ssh_test.go b/cf/ssh/ssh_test.go index 263a17a3530..8680011eaef 100644 --- a/cf/ssh/ssh_test.go +++ b/cf/ssh/ssh_test.go @@ -1,3 +1,4 @@ +//go:build !windows && !386 // +build !windows,!386 // skipping 386 because lager uses UInt64 in Session() diff --git a/cf/terminal/ui_unix.go b/cf/terminal/ui_unix.go index e62891cbc89..08ccdfbdd4a 100644 --- a/cf/terminal/ui_unix.go +++ b/cf/terminal/ui_unix.go @@ -1,5 +1,6 @@ // Copied from https://code.google.com/p/gopass/ +//go:build !windows // +build !windows package terminal diff --git a/cf/terminal/ui_windows.go b/cf/terminal/ui_windows.go index d964e5c00da..1dbe9574a6b 100644 --- a/cf/terminal/ui_windows.go +++ b/cf/terminal/ui_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package terminal diff --git a/command/flag/environment_variable_test.go b/command/flag/environment_variable_test.go index a4568586ce4..803316fe002 100644 --- a/command/flag/environment_variable_test.go +++ b/command/flag/environment_variable_test.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package flag_test diff --git a/integration/helpers/plugin_repo_platform_unix.go b/integration/helpers/plugin_repo_platform_unix.go index 97a8abf9a55..d600f7dfb9b 100644 --- a/integration/helpers/plugin_repo_platform_unix.go +++ b/integration/helpers/plugin_repo_platform_unix.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package helpers diff --git a/integration/helpers/plugin_repo_platform_windows.go b/integration/helpers/plugin_repo_platform_windows.go index b0bdc0c1ee6..e23de538bd0 100644 --- a/integration/helpers/plugin_repo_platform_windows.go +++ b/integration/helpers/plugin_repo_platform_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package helpers diff --git a/integration/shared/plugin/install_plugin_command_unix_test.go b/integration/shared/plugin/install_plugin_command_unix_test.go index dafed2ebf9b..cca2ffeee18 100644 --- a/integration/shared/plugin/install_plugin_command_unix_test.go +++ b/integration/shared/plugin/install_plugin_command_unix_test.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package plugin diff --git a/integration/shared/plugin/uninstall_plugin_command_unix_test.go b/integration/shared/plugin/uninstall_plugin_command_unix_test.go index 9ad7a6e051c..6d812450bf0 100644 --- a/integration/shared/plugin/uninstall_plugin_command_unix_test.go +++ b/integration/shared/plugin/uninstall_plugin_command_unix_test.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package plugin diff --git a/tools/tools.go b/tools/tools.go index 1316cf0af2a..e6fa2b8f2e5 100644 --- a/tools/tools.go +++ b/tools/tools.go @@ -1,3 +1,4 @@ +//go:build tools // +build tools package tools diff --git a/util/clissh/sigwinch/sigwinch.go b/util/clissh/sigwinch/sigwinch.go index ace01f9a2a2..6eab1ee5e72 100644 --- a/util/clissh/sigwinch/sigwinch.go +++ b/util/clissh/sigwinch/sigwinch.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package sigwinch diff --git a/util/clissh/sigwinch/sigwinch_win.go b/util/clissh/sigwinch/sigwinch_win.go index eac5f1ec141..045da2d6721 100644 --- a/util/clissh/sigwinch/sigwinch_win.go +++ b/util/clissh/sigwinch/sigwinch_win.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package sigwinch diff --git a/util/clissh/ssh_test.go b/util/clissh/ssh_test.go index 7bd48c47dc0..c2cd5ecbffd 100644 --- a/util/clissh/ssh_test.go +++ b/util/clissh/ssh_test.go @@ -1,3 +1,4 @@ +//go:build !windows && !386 // +build !windows,!386 // skipping 386 because lager uses UInt64 in Session() diff --git a/util/configv3/config_unix_test.go b/util/configv3/config_unix_test.go index 9c790ee1522..6af4f29361b 100644 --- a/util/configv3/config_unix_test.go +++ b/util/configv3/config_unix_test.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package configv3_test diff --git a/util/configv3/config_windows_test.go b/util/configv3/config_windows_test.go index 0c0a6016051..fad8241b3ac 100644 --- a/util/configv3/config_windows_test.go +++ b/util/configv3/config_windows_test.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package configv3_test diff --git a/util/configv3/home_dir_unix.go b/util/configv3/home_dir_unix.go index 425f34fae1a..b735d7b0797 100644 --- a/util/configv3/home_dir_unix.go +++ b/util/configv3/home_dir_unix.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package configv3 diff --git a/util/configv3/home_dir_windows.go b/util/configv3/home_dir_windows.go index 60a5f6d3143..18b1eee6787 100644 --- a/util/configv3/home_dir_windows.go +++ b/util/configv3/home_dir_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package configv3 diff --git a/util/generic/executable_filename_unix.go b/util/generic/executable_filename_unix.go index 894053524b2..65de1273664 100644 --- a/util/generic/executable_filename_unix.go +++ b/util/generic/executable_filename_unix.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package generic diff --git a/util/generic/executable_filename_unix_test.go b/util/generic/executable_filename_unix_test.go index 318268df5eb..84f4e3fd7db 100644 --- a/util/generic/executable_filename_unix_test.go +++ b/util/generic/executable_filename_unix_test.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package generic_test diff --git a/util/generic/executable_filename_windows.go b/util/generic/executable_filename_windows.go index a0a00f4c5e5..12b39103fa5 100644 --- a/util/generic/executable_filename_windows.go +++ b/util/generic/executable_filename_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package generic diff --git a/util/generic/executable_filename_windows_test.go b/util/generic/executable_filename_windows_test.go index fe0eb03c03d..bbcb8a33577 100644 --- a/util/generic/executable_filename_windows_test.go +++ b/util/generic/executable_filename_windows_test.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package generic_test diff --git a/util/manifest/manifest_unix_test.go b/util/manifest/manifest_unix_test.go index 748d5cac4cb..be5775ae881 100644 --- a/util/manifest/manifest_unix_test.go +++ b/util/manifest/manifest_unix_test.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package manifest_test diff --git a/util/manifest/manifest_windows_test.go b/util/manifest/manifest_windows_test.go index 629ce11bb8c..719b4870543 100644 --- a/util/manifest/manifest_windows_test.go +++ b/util/manifest/manifest_windows_test.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package manifest_test From 54153cb0efccb986040ec45420c9832148c1c31c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Diego=20Gonz=C3=A1lez?= <25335192+jdgonzaleza@users.noreply.github.com> Date: Tue, 8 Mar 2022 13:24:59 -0500 Subject: [PATCH 021/248] [Feature/tas-e-51] Update destination Protocol command (#2260) * Adds new update-destination command update destination app-protocol for a route so that the new protocol is used for all communication from and to the app using that route * Upgrades bundler version in integration go_ruby app Co-authored-by: Cristhian Pena Co-authored-by: George Gelashvili --- .github/CONTRIBUTING.md | 3 +- actor/v7action/cloud_controller_client.go | 1 + actor/v7action/route.go | 4 + actor/v7action/route_test.go | 43 ++ .../fake_cloud_controller_client.go | 82 ++++ .../ccv3/internal/api_routes.go | 2 + api/cloudcontroller/ccv3/route.go | 17 + api/cloudcontroller/ccv3/route_test.go | 87 ++++ command/common/command_list_v7.go | 1 + command/common/internal/help_all_display.go | 1 + command/v7/actor.go | 1 + command/v7/update_destination_command.go | 117 ++++++ command/v7/update_destination_command_test.go | 380 ++++++++++++++++++ command/v7/v7fakes/fake_actor.go | 82 ++++ integration/assets/go_calls_ruby/Gemfile.lock | 2 +- integration/helpers/app.go | 2 +- .../update_destination_command_test.go | 155 +++++++ 17 files changed, 977 insertions(+), 3 deletions(-) create mode 100644 command/v7/update_destination_command.go create mode 100644 command/v7/update_destination_command_test.go create mode 100644 integration/v7/isolated/update_destination_command_test.go diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 8ff51f43335..fcdfadb538d 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -8,7 +8,8 @@ mailing list. ## CLI Versions The cf CLI follows a branching model: -- V8 of the cf CLI is built from the [master branch](https://github.com/cloudfoundry/cli/tree/master). **This branch is under active development**. +- V9 (Next major release) of the cf CLI is built from the [master branch](https://github.com/cloudfoundry/cli/tree/master). **This branch is under active development**. +- V8 of the cf CLI is built from the [v8 branch](https://github.com/cloudfoundry/cli/tree/v8). **This branch is under active development**. - V7 of the cf CLI is built from the [v7 branch](https://github.com/cloudfoundry/cli/tree/v7). **This branch is maintenance only** and will only be updated to patch CVEs and very severe blocking defects. - V6 of the cf CLI is built from the [v6 branch](https://github.com/cloudfoundry/cli/tree/v6). **This branch is maintenance only** and will only be updated to patch CVEs and very severe blocking defects. diff --git a/actor/v7action/cloud_controller_client.go b/actor/v7action/cloud_controller_client.go index e7f87fab036..5bca12c73b0 100644 --- a/actor/v7action/cloud_controller_client.go +++ b/actor/v7action/cloud_controller_client.go @@ -162,6 +162,7 @@ type CloudControllerClient interface { UpdateApplicationRestart(appGUID string) (resources.Application, ccv3.Warnings, error) UpdateApplicationStart(appGUID string) (resources.Application, ccv3.Warnings, error) UpdateApplicationStop(appGUID string) (resources.Application, ccv3.Warnings, error) + UpdateDestination(routeGUID string, destinationGUID string, protocol string) (ccv3.Warnings, error) UpdateBuildpack(buildpack resources.Buildpack) (resources.Buildpack, ccv3.Warnings, error) UpdateEnvironmentVariableGroup(group constant.EnvironmentVariableGroupName, envVars resources.EnvironmentVariables) (resources.EnvironmentVariables, ccv3.Warnings, error) UpdateFeatureFlag(flag resources.FeatureFlag) (resources.FeatureFlag, ccv3.Warnings, error) diff --git a/actor/v7action/route.go b/actor/v7action/route.go index d59c318c61f..e91d5434473 100644 --- a/actor/v7action/route.go +++ b/actor/v7action/route.go @@ -398,6 +398,10 @@ func (actor Actor) MapRoute(routeGUID string, appGUID string, destinationProtoco return Warnings(warnings), err } +func (actor Actor) UpdateDestination(routeGUID string, destinationGUID string, protocol string) (Warnings, error) { + warnings, err := actor.CloudControllerClient.UpdateDestination(routeGUID, destinationGUID, protocol) + return Warnings(warnings), err +} func (actor Actor) UnmapRoute(routeGUID string, destinationGUID string) (Warnings, error) { warnings, err := actor.CloudControllerClient.UnmapRoute(routeGUID, destinationGUID) return Warnings(warnings), err diff --git a/actor/v7action/route_test.go b/actor/v7action/route_test.go index 064b1863761..56381a0032f 100644 --- a/actor/v7action/route_test.go +++ b/actor/v7action/route_test.go @@ -1631,6 +1631,49 @@ var _ = Describe("Route Actions", func() { }) }) + Describe("UpdateDestination", func() { + var ( + routeGUID string + destinationGUID string + protocol string + + executeErr error + warnings Warnings + ) + + JustBeforeEach(func() { + warnings, executeErr = actor.UpdateDestination(routeGUID, destinationGUID, protocol) + }) + + BeforeEach(func() { + routeGUID = "route-guid" + destinationGUID = "destination-guid" + protocol = "http2" + }) + + When("the cloud controller client errors", func() { + BeforeEach(func() { + fakeCloudControllerClient.UpdateDestinationReturns(ccv3.Warnings{"unmap-route-warning"}, errors.New("unmap-route-error")) + }) + + It("returns the error and warnings", func() { + Expect(executeErr).To(MatchError(errors.New("unmap-route-error"))) + Expect(warnings).To(ConsistOf("unmap-route-warning")) + }) + }) + + When("the cloud controller client succeeds", func() { + BeforeEach(func() { + fakeCloudControllerClient.UpdateDestinationReturns(ccv3.Warnings{"unmap-route-warning"}, nil) + }) + + It("returns the error and warnings", func() { + Expect(executeErr).ToNot(HaveOccurred()) + Expect(warnings).To(ConsistOf("unmap-route-warning")) + }) + }) + }) + Describe("DeleteOrphanedRoutes", func() { var ( spaceGUID string diff --git a/actor/v7action/v7actionfakes/fake_cloud_controller_client.go b/actor/v7action/v7actionfakes/fake_cloud_controller_client.go index 0c37e114ddf..bc955a70bba 100644 --- a/actor/v7action/v7actionfakes/fake_cloud_controller_client.go +++ b/actor/v7action/v7actionfakes/fake_cloud_controller_client.go @@ -2303,6 +2303,21 @@ type FakeCloudControllerClient struct { result2 ccv3.Warnings result3 error } + UpdateDestinationStub func(string, string, string) (ccv3.Warnings, error) + updateDestinationMutex sync.RWMutex + updateDestinationArgsForCall []struct { + arg1 string + arg2 string + arg3 string + } + updateDestinationReturns struct { + result1 ccv3.Warnings + result2 error + } + updateDestinationReturnsOnCall map[int]struct { + result1 ccv3.Warnings + result2 error + } UpdateEnvironmentVariableGroupStub func(constant.EnvironmentVariableGroupName, resources.EnvironmentVariables) (resources.EnvironmentVariables, ccv3.Warnings, error) updateEnvironmentVariableGroupMutex sync.RWMutex updateEnvironmentVariableGroupArgsForCall []struct { @@ -12694,6 +12709,71 @@ func (fake *FakeCloudControllerClient) UpdateBuildpackReturnsOnCall(i int, resul }{result1, result2, result3} } +func (fake *FakeCloudControllerClient) UpdateDestination(arg1 string, arg2 string, arg3 string) (ccv3.Warnings, error) { + fake.updateDestinationMutex.Lock() + ret, specificReturn := fake.updateDestinationReturnsOnCall[len(fake.updateDestinationArgsForCall)] + fake.updateDestinationArgsForCall = append(fake.updateDestinationArgsForCall, struct { + arg1 string + arg2 string + arg3 string + }{arg1, arg2, arg3}) + fake.recordInvocation("UpdateDestination", []interface{}{arg1, arg2, arg3}) + fake.updateDestinationMutex.Unlock() + if fake.UpdateDestinationStub != nil { + return fake.UpdateDestinationStub(arg1, arg2, arg3) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.updateDestinationReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeCloudControllerClient) UpdateDestinationCallCount() int { + fake.updateDestinationMutex.RLock() + defer fake.updateDestinationMutex.RUnlock() + return len(fake.updateDestinationArgsForCall) +} + +func (fake *FakeCloudControllerClient) UpdateDestinationCalls(stub func(string, string, string) (ccv3.Warnings, error)) { + fake.updateDestinationMutex.Lock() + defer fake.updateDestinationMutex.Unlock() + fake.UpdateDestinationStub = stub +} + +func (fake *FakeCloudControllerClient) UpdateDestinationArgsForCall(i int) (string, string, string) { + fake.updateDestinationMutex.RLock() + defer fake.updateDestinationMutex.RUnlock() + argsForCall := fake.updateDestinationArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 +} + +func (fake *FakeCloudControllerClient) UpdateDestinationReturns(result1 ccv3.Warnings, result2 error) { + fake.updateDestinationMutex.Lock() + defer fake.updateDestinationMutex.Unlock() + fake.UpdateDestinationStub = nil + fake.updateDestinationReturns = struct { + result1 ccv3.Warnings + result2 error + }{result1, result2} +} + +func (fake *FakeCloudControllerClient) UpdateDestinationReturnsOnCall(i int, result1 ccv3.Warnings, result2 error) { + fake.updateDestinationMutex.Lock() + defer fake.updateDestinationMutex.Unlock() + fake.UpdateDestinationStub = nil + if fake.updateDestinationReturnsOnCall == nil { + fake.updateDestinationReturnsOnCall = make(map[int]struct { + result1 ccv3.Warnings + result2 error + }) + } + fake.updateDestinationReturnsOnCall[i] = struct { + result1 ccv3.Warnings + result2 error + }{result1, result2} +} + func (fake *FakeCloudControllerClient) UpdateEnvironmentVariableGroup(arg1 constant.EnvironmentVariableGroupName, arg2 resources.EnvironmentVariables) (resources.EnvironmentVariables, ccv3.Warnings, error) { fake.updateEnvironmentVariableGroupMutex.Lock() ret, specificReturn := fake.updateEnvironmentVariableGroupReturnsOnCall[len(fake.updateEnvironmentVariableGroupArgsForCall)] @@ -14611,6 +14691,8 @@ func (fake *FakeCloudControllerClient) Invocations() map[string][][]interface{} defer fake.updateApplicationStopMutex.RUnlock() fake.updateBuildpackMutex.RLock() defer fake.updateBuildpackMutex.RUnlock() + fake.updateDestinationMutex.RLock() + defer fake.updateDestinationMutex.RUnlock() fake.updateEnvironmentVariableGroupMutex.RLock() defer fake.updateEnvironmentVariableGroupMutex.RUnlock() fake.updateFeatureFlagMutex.RLock() diff --git a/api/cloudcontroller/ccv3/internal/api_routes.go b/api/cloudcontroller/ccv3/internal/api_routes.go index f1d637933f3..8f2239316c8 100644 --- a/api/cloudcontroller/ccv3/internal/api_routes.go +++ b/api/cloudcontroller/ccv3/internal/api_routes.go @@ -112,6 +112,7 @@ const ( PatchApplicationFeaturesRequest = "PatchApplicationFeatures" PatchEnvironmentVariableGroupRequest = "PatchEnvironmentVariableGroup" PatchBuildpackRequest = "PatchBuildpack" + PatchDestinationRequest = "PatchDestination" PatchDomainRequest = "PatchDomain" PatchFeatureFlagRequest = "PatchFeatureFlag" PatchOrganizationRelationshipDefaultIsolationSegmentRequest = "PatchOrganizationRelationshipDefaultIsolationSegment" @@ -275,6 +276,7 @@ var APIRoutes = map[string]Route{ GetRouteDestinationsRequest: {Path: "/v3/routes/:route_guid/destinations", Method: http.MethodGet}, MapRouteRequest: {Path: "/v3/routes/:route_guid/destinations", Method: http.MethodPost}, UnmapRouteRequest: {Path: "/v3/routes/:route_guid/destinations/:destination_guid", Method: http.MethodDelete}, + PatchDestinationRequest: {Path: "/v3/routes/:route_guid/destinations/:destination_guid", Method: http.MethodPatch}, GetSecurityGroupsRequest: {Path: "/v3/security_groups", Method: http.MethodGet}, PostSecurityGroupRequest: {Path: "/v3/security_groups", Method: http.MethodPost}, DeleteSecurityGroupRequest: {Path: "/v3/security_groups/:security_group_guid", Method: http.MethodDelete}, diff --git a/api/cloudcontroller/ccv3/route.go b/api/cloudcontroller/ccv3/route.go index 947461c1ee8..b40aed980c9 100644 --- a/api/cloudcontroller/ccv3/route.go +++ b/api/cloudcontroller/ccv3/route.go @@ -131,3 +131,20 @@ func (client Client) UnmapRoute(routeGUID string, destinationGUID string) (Warni return warnings, err } + +func (client Client) UpdateDestination(routeGUID string, destinationGUID string, protocol string) (Warnings, error) { + type body struct { + Protocol string `json:"protocol"` + } + requestBody := body{ + Protocol: protocol, + } + var responseBody resources.Build + _, warnings, err := client.MakeRequest(RequestParams{ + RequestName: internal.PatchDestinationRequest, + URIParams: internal.Params{"route_guid": routeGUID, "destination_guid": destinationGUID}, + RequestBody: &requestBody, + ResponseBody: &responseBody, + }) + return warnings, err +} diff --git a/api/cloudcontroller/ccv3/route_test.go b/api/cloudcontroller/ccv3/route_test.go index 764b2787848..1ef7b6d2c5b 100644 --- a/api/cloudcontroller/ccv3/route_test.go +++ b/api/cloudcontroller/ccv3/route_test.go @@ -798,6 +798,93 @@ var _ = Describe("Route", func() { }) }) + Describe("UpdateDestination", func() { + var ( + routeGUID string + destinationGUID string + protocol string + warnings Warnings + executeErr error + ) + + JustBeforeEach(func() { + warnings, executeErr = client.UpdateDestination(routeGUID, destinationGUID, protocol) + }) + + When("the request succeeds", func() { + routeGUID = "route-guid" + destinationGUID = "destination-guid" + protocol = "http2" + + expectedBody := fmt.Sprintf(`{ + "protocol": "%s" + }`, protocol) + + BeforeEach(func() { + server.AppendHandlers( + CombineHandlers( + VerifyRequest(http.MethodPatch, "/v3/routes/route-guid/destinations/destination-guid"), + VerifyJSON(expectedBody), + RespondWith(http.StatusNoContent, nil, http.Header{ + "X-Cf-Warnings": {"this is a warning"}, + }), + ), + ) + }) + + It("returns all warnings", func() { + Expect(executeErr).NotTo(HaveOccurred()) + Expect(warnings).To(ConsistOf("this is a warning")) + }) + }) + + When("the cloud controller returns errors and warnings", func() { + BeforeEach(func() { + response := `{ + "errors": [ + { + "code": 10008, + "detail": "The request is semantically invalid: command presence", + "title": "CF-UnprocessableEntity" + }, + { + "code": 10010, + "detail": "Isolation segment not found", + "title": "CF-ResourceNotFound" + } + ] + }` + server.AppendHandlers( + CombineHandlers( + VerifyRequest(http.MethodPatch, "/v3/routes/route-guid/destinations/destination-guid"), + RespondWith(http.StatusTeapot, response, http.Header{ + "X-Cf-Warnings": {"this is a warning"}, + }), + ), + ) + }) + + It("returns the error and all warnings", func() { + Expect(executeErr).To(MatchError(ccerror.MultiError{ + ResponseCode: http.StatusTeapot, + Errors: []ccerror.V3Error{ + { + Code: 10008, + Detail: "The request is semantically invalid: command presence", + Title: "CF-UnprocessableEntity", + }, + { + Code: 10010, + Detail: "Isolation segment not found", + Title: "CF-ResourceNotFound", + }, + }, + })) + Expect(warnings).To(ConsistOf("this is a warning")) + }) + }) + }) + Describe("DeleteOrphanedRoutes", func() { var ( spaceGUID string diff --git a/command/common/command_list_v7.go b/command/common/command_list_v7.go index 6cb264ed745..83300833d79 100644 --- a/command/common/command_list_v7.go +++ b/command/common/command_list_v7.go @@ -187,6 +187,7 @@ type commandList struct { UnsharePrivateDomain v7.UnsharePrivateDomainCommand `command:"unshare-private-domain" description:"Unshare a private domain with a specific org"` UnshareService v7.UnshareServiceCommand `command:"unshare-service" description:"Unshare a shared service instance from a space"` UpdateBuildpack v7.UpdateBuildpackCommand `command:"update-buildpack" description:"Update a buildpack"` + UpdateDestination v7.UpdateDestinationCommand `command:"update-destination" description:"Updates the destination protocol for a route"` UpdateOrgQuota v7.UpdateOrgQuotaCommand `command:"update-org-quota" alias:"update-quota" description:"Update an existing organization quota"` UpdateSecurityGroup v7.UpdateSecurityGroupCommand `command:"update-security-group" description:"Update a security group"` UpdateService v7.UpdateServiceCommand `command:"update-service" description:"Update a service instance"` diff --git a/command/common/internal/help_all_display.go b/command/common/internal/help_all_display.go index 3dac8169748..e6d19c3d859 100644 --- a/command/common/internal/help_all_display.go +++ b/command/common/internal/help_all_display.go @@ -67,6 +67,7 @@ var HelpCategoryList = []HelpCategory{ {"routes", "route"}, {"create-route", "check-route", "map-route", "unmap-route", "delete-route"}, {"delete-orphaned-routes"}, + {"update-destination"}, }, }, { diff --git a/command/v7/actor.go b/command/v7/actor.go index d8bc2a17dca..b62365e4a90 100644 --- a/command/v7/actor.go +++ b/command/v7/actor.go @@ -232,6 +232,7 @@ type Actor interface { UpdateApplicationLabelsByApplicationName(string, string, map[string]types.NullString) (v7action.Warnings, error) UpdateBuildpackByNameAndStack(buildpackName string, buildpackStack string, buildpack resources.Buildpack) (resources.Buildpack, v7action.Warnings, error) UpdateBuildpackLabelsByBuildpackNameAndStack(string, string, map[string]types.NullString) (v7action.Warnings, error) + UpdateDestination(string, string, string) (v7action.Warnings, error) UpdateDomainLabelsByDomainName(string, map[string]types.NullString) (v7action.Warnings, error) UpdateManagedServiceInstance(params v7action.UpdateManagedServiceInstanceParams) (chan v7action.PollJobEvent, v7action.Warnings, error) UpgradeManagedServiceInstance(serviceInstanceName, spaceGUID string) (v7action.Warnings, error) diff --git a/command/v7/update_destination_command.go b/command/v7/update_destination_command.go new file mode 100644 index 00000000000..082b693db3f --- /dev/null +++ b/command/v7/update_destination_command.go @@ -0,0 +1,117 @@ +package v7 + +import ( + "errors" + + "code.cloudfoundry.org/cli/actor/actionerror" + "code.cloudfoundry.org/cli/command/flag" +) + +type UpdateDestinationCommand struct { + BaseCommand + + RequiredArgs flag.AppDomain `positional-args:"yes"` + Hostname string `long:"hostname" short:"n" description:"Hostname for the HTTP route (required for shared domains)"` + AppProtocol string `long:"app-protocol" description:"New Protocol for the route destination (http1 or http2). Only applied to HTTP routes"` + Path flag.V7RoutePath `long:"path" description:"Path for the HTTP route"` + + relatedCommands interface{} `related_commands:"routes, map-route, create-route, unmap-route"` +} + +func (cmd UpdateDestinationCommand) Usage() string { + return ` +Edit an existing HTTP route: + CF_NAME update-destination APP_NAME DOMAIN [--hostname HOSTNAME] [--app-protocol PROTOCOL] [--path PATH]` +} + +func (cmd UpdateDestinationCommand) Examples() string { + return ` +CF_NAME update-destination my-app example.com --hostname myhost --app-protocol http2 # myhost.example.com +CF_NAME update destination my-app example.com --hostname myhost --path foo --app-protocol http2 # myhost.example.com/foo` +} + +func (cmd UpdateDestinationCommand) Execute(args []string) error { + err := cmd.SharedActor.CheckTarget(true, true) + if err != nil { + return err + } + + user, err := cmd.Actor.GetCurrentUser() + if err != nil { + return err + } + + domain, warnings, err := cmd.Actor.GetDomainByName(cmd.RequiredArgs.Domain) + cmd.UI.DisplayWarnings(warnings) + if err != nil { + return err + } + + spaceGUID := cmd.Config.TargetedSpace().GUID + app, warnings, err := cmd.Actor.GetApplicationByNameAndSpace(cmd.RequiredArgs.App, spaceGUID) + cmd.UI.DisplayWarnings(warnings) + if err != nil { + return err + } + + path := cmd.Path.Path + route, warnings, err := cmd.Actor.GetRouteByAttributes(domain, cmd.Hostname, path, 0) + cmd.UI.DisplayWarnings(warnings) + url := desiredURL(domain.Name, cmd.Hostname, path, 0) + if err != nil { + if _, ok := err.(actionerror.RouteNotFoundError); ok { + cmd.UI.DisplayText("Route to be updated does not exist.") + return err + } + return err + } + + dest, err := cmd.Actor.GetRouteDestinationByAppGUID(route, app.GUID) + if err != nil { + if _, ok := err.(actionerror.RouteDestinationNotFoundError); !ok { + cmd.UI.DisplayText("Route's destination to be updated does not exist.") + return err + } + } + + if cmd.AppProtocol == "" { + cmd.AppProtocol = "http1" + } + + if cmd.AppProtocol == "tcp" { + return errors.New("Destination protocol must be 'http1' or 'http2'") + } + + if dest.Protocol == cmd.AppProtocol { + cmd.UI.DisplayText(" App '{{ .AppName }}' is already using '{{ .AppProtocol }}'. Nothing has been updated", map[string]interface{}{ + "AppName": cmd.RequiredArgs.App, + "AppProtocol": cmd.AppProtocol, + }) + cmd.UI.DisplayOK() + return nil + } + + cmd.UI.DisplayTextWithFlavor("Updating destination protocol from {{.OldProtocol}} to {{.NewProtocol}} for route {{.URL}} in org {{.OrgName}} / space {{.SpaceName}} as {{.User}}...", + map[string]interface{}{ + "OldProtocol": dest.Protocol, + "NewProtocol": cmd.AppProtocol, + "URL": url, + "User": user.Name, + "SpaceName": cmd.Config.TargetedSpace().Name, + "OrgName": cmd.Config.TargetedOrganization().Name, + }) + + warnings, err = cmd.Actor.UpdateDestination( + route.GUID, + dest.GUID, + cmd.AppProtocol, + ) + + cmd.UI.DisplayWarnings(warnings) + if err != nil { + return err + } + cmd.UI.DisplayOK() + + return nil +} diff --git a/command/v7/update_destination_command_test.go b/command/v7/update_destination_command_test.go new file mode 100644 index 00000000000..802a125b7ce --- /dev/null +++ b/command/v7/update_destination_command_test.go @@ -0,0 +1,380 @@ +package v7_test + +import ( + "code.cloudfoundry.org/cli/actor/actionerror" + "code.cloudfoundry.org/cli/actor/v7action" + "code.cloudfoundry.org/cli/cf/errors" + "code.cloudfoundry.org/cli/command/commandfakes" + "code.cloudfoundry.org/cli/command/flag" + v7 "code.cloudfoundry.org/cli/command/v7" + "code.cloudfoundry.org/cli/command/v7/v7fakes" + "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/configv3" + "code.cloudfoundry.org/cli/util/ui" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gbytes" +) + +var _ = Describe("update Command", func() { + var ( + cmd v7.UpdateDestinationCommand + testUI *ui.UI + fakeConfig *commandfakes.FakeConfig + fakeSharedActor *commandfakes.FakeSharedActor + fakeActor *v7fakes.FakeActor + binaryName string + executeErr error + domainName string + appName string + appProtocol string + orgGUID string + spaceGUID string + hostname string + path string + ) + + BeforeEach(func() { + testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) + fakeConfig = new(commandfakes.FakeConfig) + fakeSharedActor = new(commandfakes.FakeSharedActor) + fakeActor = new(v7fakes.FakeActor) + + binaryName = "faceman" + fakeConfig.BinaryNameReturns(binaryName) + + domainName = "some-domain.com" + appName = "super-app" + appProtocol = "http2" + orgGUID = "some-org-guid" + spaceGUID = "some-space-guid" + hostname = "hostname" + path = "path" + + cmd = v7.UpdateDestinationCommand{ + BaseCommand: v7.BaseCommand{ + UI: testUI, + Config: fakeConfig, + SharedActor: fakeSharedActor, + Actor: fakeActor, + }, + RequiredArgs: flag.AppDomain{App: appName, Domain: domainName}, + AppProtocol: appProtocol, + Hostname: hostname, + Path: flag.V7RoutePath{Path: path}, + } + + fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "some-space", GUID: spaceGUID}) + fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org", GUID: orgGUID}) + fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + + }) + + JustBeforeEach(func() { + executeErr = cmd.Execute(nil) + }) + + It("checks the target", func() { + Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) + checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) + Expect(checkTargetedOrg).To(BeTrue()) + Expect(checkTargetedSpace).To(BeTrue()) + }) + + When("checking target fails", func() { + BeforeEach(func() { + fakeSharedActor.CheckTargetReturns(actionerror.NoOrganizationTargetedError{BinaryName: binaryName}) + }) + It("returns an error", func() { + Expect(executeErr).To(MatchError(actionerror.NoOrganizationTargetedError{BinaryName: binaryName})) + + Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) + checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) + Expect(checkTargetedOrg).To(BeTrue()) + Expect(checkTargetedSpace).To(BeTrue()) + }) + }) + + When("the user is not logged in", func() { + var expectedErr error + + BeforeEach(func() { + expectedErr = errors.New("some current user error") + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) + }) + + It("return an error", func() { + Expect(executeErr).To(Equal(expectedErr)) + }) + }) + + When("the user is logged in and targeted", func() { + When("getting the domain errors", func() { + BeforeEach(func() { + fakeActor.GetDomainByNameReturns(resources.Domain{}, v7action.Warnings{"get-domain-warnings"}, errors.New("get-domain-error")) + }) + It("returns the error and displays warnings", func() { + Expect(testUI.Err).To(Say("get-domain-warnings")) + Expect(executeErr).To(MatchError(errors.New("get-domain-error"))) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(0)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(0)) + + Expect(fakeActor.GetRouteDestinationByAppGUIDCallCount()).To(Equal(0)) + + Expect(fakeActor.UpdateDestinationCallCount()).To(Equal(0)) + }) + }) + + When("getting the domain succeeds", func() { + BeforeEach(func() { + fakeActor.GetDomainByNameReturns( + resources.Domain{Name: domainName, GUID: "domain-guid"}, + v7action.Warnings{"get-domain-warnings"}, + nil, + ) + }) + + When("getting the app errors", func() { + BeforeEach(func() { + fakeActor.GetApplicationByNameAndSpaceReturns( + resources.Application{}, + v7action.Warnings{"get-app-warnings"}, + errors.New("get-app-error"), + ) + }) + It("returns the error and displays warnings", func() { + Expect(testUI.Err).To(Say("get-domain-warnings")) + Expect(testUI.Err).To(Say("get-app-warnings")) + Expect(executeErr).To(MatchError(errors.New("get-app-error"))) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1)) + actualAppName, actualSpaceGUID := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0) + Expect(actualAppName).To(Equal(appName)) + Expect(actualSpaceGUID).To(Equal(spaceGUID)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(0)) + + Expect(fakeActor.CreateRouteCallCount()).To(Equal(0)) + + Expect(fakeActor.MapRouteCallCount()).To(Equal(0)) + }) + }) + + When("getting the app succeeds", func() { + BeforeEach(func() { + fakeActor.GetApplicationByNameAndSpaceReturns( + resources.Application{GUID: "app-guid", Name: appName}, + v7action.Warnings{"get-app-warnings"}, + nil, + ) + }) + + When("getting the route errors", func() { + BeforeEach(func() { + fakeActor.GetRouteByAttributesReturns( + resources.Route{}, + v7action.Warnings{"get-route-warnings"}, + errors.New("get-route-error"), + ) + }) + + It("returns the error and displays warnings", func() { + Expect(testUI.Err).To(Say("get-domain-warnings")) + Expect(testUI.Err).To(Say("get-app-warnings")) + Expect(testUI.Err).To(Say("get-route-warnings")) + Expect(executeErr).To(MatchError(errors.New("get-route-error"))) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1)) + actualAppName, actualSpaceGUID := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0) + Expect(actualAppName).To(Equal(appName)) + Expect(actualSpaceGUID).To(Equal(spaceGUID)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + + Expect(fakeActor.UpdateDestinationCallCount()).To(Equal(0)) + + }) + }) + + When("the requested route does not exist", func() { + BeforeEach(func() { + fakeActor.GetRouteByAttributesReturns( + resources.Route{}, + v7action.Warnings{"get-route-warnings"}, + actionerror.RouteNotFoundError{}, + ) + }) + + It("displays error message", func() { + Expect(testUI.Err).To(Say("get-domain-warnings")) + Expect(testUI.Err).To(Say("get-route-warnings")) + Expect(executeErr).To(HaveOccurred()) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1)) + actualAppName, actualSpaceGUID := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0) + Expect(actualAppName).To(Equal(appName)) + Expect(actualSpaceGUID).To(Equal(spaceGUID)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + }) + }) + + When("the requested route exists", func() { + BeforeEach(func() { + fakeActor.GetRouteByAttributesReturns( + resources.Route{GUID: "route-guid"}, + v7action.Warnings{"get-route-warnings"}, + nil, + ) + }) + When("getting the destination errors", func() { + BeforeEach(func() { + fakeActor.GetRouteDestinationByAppGUIDReturns( + resources.RouteDestination{}, + errors.New("get-destination-error"), + ) + }) + It("returns the error and warnings", func() { + Expect(executeErr).To(MatchError(errors.New("get-destination-error"))) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1)) + actualAppName, actualSpaceGUID := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0) + Expect(actualAppName).To(Equal(appName)) + Expect(actualSpaceGUID).To(Equal(spaceGUID)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + + Expect(fakeActor.GetRouteDestinationByAppGUIDCallCount()).To(Equal(1)) + actualRoute, actualAppGUID := fakeActor.GetRouteDestinationByAppGUIDArgsForCall(0) + Expect(actualRoute.GUID).To(Equal("route-guid")) + Expect(actualAppGUID).To(Equal("app-guid")) + + Expect(fakeActor.UpdateDestinationCallCount()).To(Equal(0)) + }) + }) + When("the destination already exists", func() { + BeforeEach(func() { + fakeActor.GetRouteDestinationByAppGUIDReturns( + resources.RouteDestination{ + GUID: "route-dst-guid", + App: resources.RouteDestinationApp{ + GUID: "existing-app-guid", + }, + }, + nil, + ) + }) + + It("exits 0 with a helpful message that the destination protocol was changed", func() { + Expect(executeErr).ShouldNot(HaveOccurred()) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1)) + actualAppName, actualSpaceGUID := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0) + Expect(actualAppName).To(Equal(appName)) + Expect(actualSpaceGUID).To(Equal(spaceGUID)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + + Expect(fakeActor.GetRouteDestinationByAppGUIDCallCount()).To(Equal(1)) + actualRoute, actualAppGUID := fakeActor.GetRouteDestinationByAppGUIDArgsForCall(0) + Expect(actualRoute.GUID).To(Equal("route-guid")) + Expect(actualAppGUID).To(Equal("app-guid")) + Expect(fakeActor.UpdateDestinationCallCount()).To(Equal(1)) + }) + }) + + When("the destination is not found", func() { + When("updating the destination errors", func() { + BeforeEach(func() { + fakeActor.UpdateDestinationReturns(v7action.Warnings{"update-dest-warnings"}, errors.New("map-route-error")) + fakeActor.GetRouteDestinationByAppGUIDReturns( + resources.RouteDestination{ + GUID: "route-dst-guid", + App: resources.RouteDestinationApp{ + GUID: "existing-app-guid", + }, + }, + nil, + ) + }) + + It("returns the error and displays warnings", func() { + Expect(testUI.Err).To(Say("get-domain-warnings")) + Expect(testUI.Err).To(Say("get-app-warnings")) + Expect(testUI.Err).To(Say("get-route-warnings")) + Expect(testUI.Err).To(Say("update-dest-warnings")) + Expect(executeErr).To(MatchError(errors.New("map-route-error"))) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1)) + actualAppName, actualSpaceGUID := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0) + Expect(actualAppName).To(Equal(appName)) + Expect(actualSpaceGUID).To(Equal(spaceGUID)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + + Expect(fakeActor.UpdateDestinationCallCount()).To(Equal(1)) + actualRouteGUID, destinationGUID, protocol := fakeActor.UpdateDestinationArgsForCall(0) + Expect(actualRouteGUID).To(Equal("route-guid")) + Expect(destinationGUID).To(Equal("route-dst-guid")) + Expect(protocol).To(Equal("http2")) + }) + }) + }) + }) + }) + }) + }) +}) diff --git a/command/v7/v7fakes/fake_actor.go b/command/v7/v7fakes/fake_actor.go index 8065bc84341..523de5ea272 100644 --- a/command/v7/v7fakes/fake_actor.go +++ b/command/v7/v7fakes/fake_actor.go @@ -3213,6 +3213,21 @@ type FakeActor struct { result1 v7action.Warnings result2 error } + UpdateDestinationStub func(string, string, string) (v7action.Warnings, error) + updateDestinationMutex sync.RWMutex + updateDestinationArgsForCall []struct { + arg1 string + arg2 string + arg3 string + } + updateDestinationReturns struct { + result1 v7action.Warnings + result2 error + } + updateDestinationReturnsOnCall map[int]struct { + result1 v7action.Warnings + result2 error + } UpdateDomainLabelsByDomainNameStub func(string, map[string]types.NullString) (v7action.Warnings, error) updateDomainLabelsByDomainNameMutex sync.RWMutex updateDomainLabelsByDomainNameArgsForCall []struct { @@ -17339,6 +17354,71 @@ func (fake *FakeActor) UpdateBuildpackLabelsByBuildpackNameAndStackReturnsOnCall }{result1, result2} } +func (fake *FakeActor) UpdateDestination(arg1 string, arg2 string, arg3 string) (v7action.Warnings, error) { + fake.updateDestinationMutex.Lock() + ret, specificReturn := fake.updateDestinationReturnsOnCall[len(fake.updateDestinationArgsForCall)] + fake.updateDestinationArgsForCall = append(fake.updateDestinationArgsForCall, struct { + arg1 string + arg2 string + arg3 string + }{arg1, arg2, arg3}) + fake.recordInvocation("UpdateDestination", []interface{}{arg1, arg2, arg3}) + fake.updateDestinationMutex.Unlock() + if fake.UpdateDestinationStub != nil { + return fake.UpdateDestinationStub(arg1, arg2, arg3) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.updateDestinationReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeActor) UpdateDestinationCallCount() int { + fake.updateDestinationMutex.RLock() + defer fake.updateDestinationMutex.RUnlock() + return len(fake.updateDestinationArgsForCall) +} + +func (fake *FakeActor) UpdateDestinationCalls(stub func(string, string, string) (v7action.Warnings, error)) { + fake.updateDestinationMutex.Lock() + defer fake.updateDestinationMutex.Unlock() + fake.UpdateDestinationStub = stub +} + +func (fake *FakeActor) UpdateDestinationArgsForCall(i int) (string, string, string) { + fake.updateDestinationMutex.RLock() + defer fake.updateDestinationMutex.RUnlock() + argsForCall := fake.updateDestinationArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 +} + +func (fake *FakeActor) UpdateDestinationReturns(result1 v7action.Warnings, result2 error) { + fake.updateDestinationMutex.Lock() + defer fake.updateDestinationMutex.Unlock() + fake.UpdateDestinationStub = nil + fake.updateDestinationReturns = struct { + result1 v7action.Warnings + result2 error + }{result1, result2} +} + +func (fake *FakeActor) UpdateDestinationReturnsOnCall(i int, result1 v7action.Warnings, result2 error) { + fake.updateDestinationMutex.Lock() + defer fake.updateDestinationMutex.Unlock() + fake.UpdateDestinationStub = nil + if fake.updateDestinationReturnsOnCall == nil { + fake.updateDestinationReturnsOnCall = make(map[int]struct { + result1 v7action.Warnings + result2 error + }) + } + fake.updateDestinationReturnsOnCall[i] = struct { + result1 v7action.Warnings + result2 error + }{result1, result2} +} + func (fake *FakeActor) UpdateDomainLabelsByDomainName(arg1 string, arg2 map[string]types.NullString) (v7action.Warnings, error) { fake.updateDomainLabelsByDomainNameMutex.Lock() ret, specificReturn := fake.updateDomainLabelsByDomainNameReturnsOnCall[len(fake.updateDomainLabelsByDomainNameArgsForCall)] @@ -19266,6 +19346,8 @@ func (fake *FakeActor) Invocations() map[string][][]interface{} { defer fake.updateBuildpackByNameAndStackMutex.RUnlock() fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.RLock() defer fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.RUnlock() + fake.updateDestinationMutex.RLock() + defer fake.updateDestinationMutex.RUnlock() fake.updateDomainLabelsByDomainNameMutex.RLock() defer fake.updateDomainLabelsByDomainNameMutex.RUnlock() fake.updateManagedServiceInstanceMutex.RLock() diff --git a/integration/assets/go_calls_ruby/Gemfile.lock b/integration/assets/go_calls_ruby/Gemfile.lock index f1d8dee14cd..51e876ea324 100644 --- a/integration/assets/go_calls_ruby/Gemfile.lock +++ b/integration/assets/go_calls_ruby/Gemfile.lock @@ -8,4 +8,4 @@ PLATFORMS DEPENDENCIES BUNDLED WITH - 1.14.6 + 2.2.27 diff --git a/integration/helpers/app.go b/integration/helpers/app.go index df93f60ac7e..92cccfa3902 100644 --- a/integration/helpers/app.go +++ b/integration/helpers/app.go @@ -194,7 +194,7 @@ PLATFORMS DEPENDENCIES BUNDLED WITH - 1.15.0 + 2.1.4 `), 0666) Expect(err).ToNot(HaveOccurred()) diff --git a/integration/v7/isolated/update_destination_command_test.go b/integration/v7/isolated/update_destination_command_test.go new file mode 100644 index 00000000000..6052d8795b3 --- /dev/null +++ b/integration/v7/isolated/update_destination_command_test.go @@ -0,0 +1,155 @@ +package isolated + +import ( + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" + . "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers" + "code.cloudfoundry.org/cli/integration/helpers" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gbytes" + . "github.com/onsi/gomega/gexec" +) + +var _ = Describe("update destination command", func() { + Context("Heltp", func() { + It("appears in cf help -a", func() { + session := helpers.CF("help", "-a") + + Eventually(session).Should(Exit(0)) + Expect(session).To(HaveCommandInCategoryWithDescription("update-destination", "ROUTES", "Updates the destination protocol for a route")) + }) + + It("displays the help information", func() { + session := helpers.CF("update-destination", "--help") + Eventually(session).Should(Say(`NAME:`)) + Eventually(session).Should(Say(`update-destination - Updates the destination protocol for a route`)) + Eventually(session).Should(Say(`\n`)) + + Eventually(session).Should(Say(`USAGE:`)) + Eventually(session).Should(Say(`Edit an existing HTTP route`)) + Eventually(session).Should(Say(`cf update-destination APP_NAME DOMAIN \[--hostname HOSTNAME\] \[--app-protocol PROTOCOL\] \[--path PATH\]\n`)) + Eventually(session).Should(Say(`\n`)) + + Eventually(session).Should(Say(`EXAMPLES:`)) + Eventually(session).Should(Say(`cf update-destination my-app example.com --hostname myhost --app-protocol http2 # myhost.example.com`)) + Eventually(session).Should(Say(`cf update destination my-app example.com --hostname myhost --path foo --app-protocol http2 # myhost.example.com/foo`)) + Eventually(session).Should(Say(`\n`)) + + Eventually(session).Should(Say(`OPTIONS:`)) + Eventually(session).Should(Say(`--hostname, -n\s+Hostname for the HTTP route \(required for shared domains\)`)) + Eventually(session).Should(Say(`--app-protocol\s+New Protocol for the route destination \(http1 or http2\). Only applied to HTTP routes`)) + Eventually(session).Should(Say(`--path\s+Path for the HTTP route`)) + Eventually(session).Should(Say(`\n`)) + + Eventually(session).Should(Say(`SEE ALSO:`)) + Eventually(session).Should(Say(`create-route, map-route, routes, unmap-route`)) + + Eventually(session).Should(Exit(0)) + }) + }) + + When("the environment is not setup correctly", func() { + It("fails with the appropriate errors", func() { + helpers.CheckEnvironmentTargetedCorrectly(true, false, ReadOnlyOrg, "update-destination", "app-name", "some-domain") + }) + }) + + When("the environment is set up correctly", func() { + var ( + userName string + orgName string + spaceName string + ) + + BeforeEach(func() { + helpers.SkipIfVersionLessThan(ccversion.MinVersionHTTP2RoutingV3) + orgName = helpers.NewOrgName() + spaceName = helpers.NewSpaceName() + + helpers.SetupCF(orgName, spaceName) + userName, _ = helpers.GetCredentials() + }) + + AfterEach(func() { + helpers.QuickDeleteOrg(orgName) + }) + + When("the domain exists", func() { + var ( + domainName string + ) + + BeforeEach(func() { + domainName = helpers.NewDomainName() + }) + + When("the route exists", func() { + var ( + domain helpers.Domain + appName string + hostname string + ) + + When("it's an HTTP/1 route", func() { + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "key-lime-pie" + appName = "killer" + domain.CreatePrivate() + Eventually(helpers.CF("create-app", appName)).Should(Exit(0)) + Eventually(helpers.CF("create-route", domain.Name, "--hostname", hostname)).Should(Exit(0)) + Eventually(helpers.CF("map-route", appName, domain.Name, "--hostname", hostname)).Should(Exit(0)) + }) + + AfterEach(func() { + domain.Delete() + }) + + It("updates the destination protocol to http2 ", func() { + session := helpers.CF("update-destination", appName, domainName, "--hostname", hostname, "--app-protocol", "http2") + Eventually(session).Should(Say(`Updating destination protocol from %s to %s for route %s.%s in org %s / space %s as %s...`, "http1", "http2", hostname, domainName, orgName, spaceName, userName)) + Eventually(session).Should(Say(`OK`)) + Eventually(session).Should(Exit(0)) + }) + }) + + When("it's an HTTP/2 route", func() { + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "key-lime-pie" + appName = "killer2" + domain.CreatePrivate() + Eventually(helpers.CF("create-app", appName)).Should(Exit(0)) + Eventually(helpers.CF("create-route", domain.Name, "--hostname", hostname)).Should(Exit(0)) + Eventually(helpers.CF("map-route", appName, domain.Name, "--hostname", hostname, "--app-protocol", "http2")).Should(Exit(0)) + }) + + AfterEach(func() { + domain.Delete() + }) + + It("updates the destination protocol to http1 ", func() { + session := helpers.CF("update-destination", appName, domainName, "--hostname", hostname, "--app-protocol", "http1") + Eventually(session).Should(Say(`Updating destination protocol from %s to %s for route %s.%s in org %s / space %s as %s...`, "http2", "http1", hostname, domainName, orgName, spaceName, userName)) + Eventually(session).Should(Say(`OK`)) + Eventually(session).Should(Exit(0)) + }) + + It("does nothing when the app-protocol is the same", func() { + session := helpers.CF("update-destination", appName, domainName, "--hostname", hostname, "--app-protocol", "http2") + Eventually(session).Should(Say(`App '%s' is already using '%s'\. Nothing has been updated`, appName, "http2")) + Eventually(session).Should(Say(`OK`)) + Eventually(session).Should(Exit(0)) + }) + + It("sets the destination protocol to 'http1' when the app-protocol is not provided", func() { + session := helpers.CF("update-destination", appName, domainName, "--hostname", hostname) + Eventually(session).Should(Say(`Updating destination protocol from %s to %s for route %s.%s in org %s / space %s as %s...`, "http2", "http1", hostname, domainName, orgName, spaceName, userName)) + Eventually(session).Should(Say(`OK`)) + Eventually(session).Should(Exit(0)) + }) + }) + }) + }) + }) +}) From bef87cf76df38801363cd697edc5e256af04220a Mon Sep 17 00:00:00 2001 From: Juan Diego Gonzalez Date: Tue, 8 Mar 2022 18:28:12 +0000 Subject: [PATCH 022/248] Bumps BUILD_VERSION --- BUILD_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD_VERSION b/BUILD_VERSION index fbb9ea12de3..2bf50aaf17a 100644 --- a/BUILD_VERSION +++ b/BUILD_VERSION @@ -1 +1 @@ -8.2.0 +8.3.0 From 2b4e14408be4e571fdb95ebbf4065433c5f10efe Mon Sep 17 00:00:00 2001 From: Hector J Calderon Date: Wed, 9 Feb 2022 15:36:49 -0500 Subject: [PATCH 023/248] [Bugfix] Idempotency when trying to create a service twice It was implemented everything for this feature but the error handler when CAPI V3 answered with a 422 status code with the message the service instance name is taken. --- api/cloudcontroller/ccv3/errors.go | 3 +++ api/cloudcontroller/ccv3/errors_test.go | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/api/cloudcontroller/ccv3/errors.go b/api/cloudcontroller/ccv3/errors.go index 1a593a5fe1f..c89a60d126a 100644 --- a/api/cloudcontroller/ccv3/errors.go +++ b/api/cloudcontroller/ccv3/errors.go @@ -171,6 +171,9 @@ func handleUnprocessableEntity(errorResponse ccerror.V3Error) error { case strings.Contains(errorString, "Assign a droplet before starting this app."): return ccerror.InvalidStartError{} + case strings.Contains(errorString, + "The service instance name is taken"): + return ccerror.ServiceInstanceNameTakenError{Message: err.Message} case orgNameTakenRegexp.MatchString(errorString): return ccerror.OrganizationNameTakenError{UnprocessableEntityError: err} case roleExistsRegexp.MatchString(errorString): diff --git a/api/cloudcontroller/ccv3/errors_test.go b/api/cloudcontroller/ccv3/errors_test.go index 8785a9a848c..6873746014c 100644 --- a/api/cloudcontroller/ccv3/errors_test.go +++ b/api/cloudcontroller/ccv3/errors_test.go @@ -486,6 +486,27 @@ var _ = Describe("Error Wrapper", func() { }) }) + When("the service instance name is taken", func() { + BeforeEach(func() { + serverResponse = ` +{ + "errors": [ + { + "code": 10008, + "detail": "The service instance name is taken", + "title": "CF-UnprocessableEntity" + } + ] +}` + }) + + It("returns an ServiceInstanceNameTakenError", func() { + Expect(makeError).To(MatchError(ccerror.ServiceInstanceNameTakenError{ + Message: "The service instance name is taken", + })) + }) + }) + When("the buildpack is invalid", func() { BeforeEach(func() { serverResponse = ` From 375a05cbf4364d571814cef23fd23d55151f303e Mon Sep 17 00:00:00 2001 From: Matt Royal Date: Fri, 11 Mar 2022 14:49:51 -0800 Subject: [PATCH 024/248] Fix selfcontained tests failing due to /whoami Authored-by: Matt Royal --- .../v7/selfcontained/kubernetes_auth_test.go | 20 ++++-- .../v7/selfcontained/login_command_test.go | 17 +++-- .../v7/selfcontained/logout_command_test.go | 71 +++++++++++++++++-- 3 files changed, 93 insertions(+), 15 deletions(-) diff --git a/integration/v7/selfcontained/kubernetes_auth_test.go b/integration/v7/selfcontained/kubernetes_auth_test.go index 113c8e4f175..dfaa8d8bfa0 100644 --- a/integration/v7/selfcontained/kubernetes_auth_test.go +++ b/integration/v7/selfcontained/kubernetes_auth_test.go @@ -4,14 +4,15 @@ import ( "net/http" "path/filepath" - "code.cloudfoundry.org/cli/integration/helpers" - "code.cloudfoundry.org/cli/integration/v7/selfcontained/fake" - "code.cloudfoundry.org/cli/resources" - "code.cloudfoundry.org/cli/util/configv3" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" apiv1 "k8s.io/client-go/tools/clientcmd/api/v1" + + "code.cloudfoundry.org/cli/integration/helpers" + "code.cloudfoundry.org/cli/integration/v7/selfcontained/fake" + "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/configv3" ) var _ = Describe("auth-provider", func() { @@ -29,13 +30,19 @@ var _ = Describe("auth-provider", func() { "resources": []resources.Application{}, }, }, + "GET /whoami": { + Code: http.StatusOK, Body: map[string]interface{}{ + "name": "my-user", + "kind": "User", + }, + }, }, } apiServer.SetConfiguration(apiConfig) helpers.SetConfig(func(config *configv3.Config) { config.ConfigFile.Target = apiServer.URL() config.ConfigFile.CFOnK8s.Enabled = true - config.ConfigFile.CFOnK8s.AuthInfo = "one" + config.ConfigFile.CFOnK8s.AuthInfo = "my-user" config.ConfigFile.TargetedOrganization = configv3.Organization{ GUID: "my-org", Name: "My Org", @@ -52,7 +59,8 @@ var _ = Describe("auth-provider", func() { APIVersion: "v1", AuthInfos: []apiv1.NamedAuthInfo{ { - Name: "one", AuthInfo: apiv1.AuthInfo{ + Name: "my-user", + AuthInfo: apiv1.AuthInfo{ AuthProvider: &apiv1.AuthProviderConfig{ Name: "oidc", Config: map[string]string{ diff --git a/integration/v7/selfcontained/login_command_test.go b/integration/v7/selfcontained/login_command_test.go index 5e41d783fec..5def6b7b457 100644 --- a/integration/v7/selfcontained/login_command_test.go +++ b/integration/v7/selfcontained/login_command_test.go @@ -6,16 +6,17 @@ import ( "os" "path/filepath" - "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" - "code.cloudfoundry.org/cli/integration/helpers" - "code.cloudfoundry.org/cli/integration/v7/selfcontained/fake" - "code.cloudfoundry.org/cli/resources" - "code.cloudfoundry.org/cli/util/configv3" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gexec" apiv1 "k8s.io/client-go/tools/clientcmd/api/v1" + + "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" + "code.cloudfoundry.org/cli/integration/helpers" + "code.cloudfoundry.org/cli/integration/v7/selfcontained/fake" + "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/configv3" ) var _ = Describe("LoginCommand", func() { @@ -45,6 +46,12 @@ var _ = Describe("LoginCommand", func() { "resources": []resources.Organization{}, }, }, + "GET /whoami": { + Code: http.StatusOK, Body: map[string]interface{}{ + "name": "two", + "kind": "User", + }, + }, }, } apiServer.SetConfiguration(apiConfig) diff --git a/integration/v7/selfcontained/logout_command_test.go b/integration/v7/selfcontained/logout_command_test.go index 55e53f35a5d..b607be4146a 100644 --- a/integration/v7/selfcontained/logout_command_test.go +++ b/integration/v7/selfcontained/logout_command_test.go @@ -1,23 +1,86 @@ package selfcontained_test import ( - "code.cloudfoundry.org/cli/integration/helpers" - "code.cloudfoundry.org/cli/util/configv3" + "net/http" + "path/filepath" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" + apiv1 "k8s.io/client-go/tools/clientcmd/api/v1" + + "code.cloudfoundry.org/cli/integration/helpers" + "code.cloudfoundry.org/cli/integration/v7/selfcontained/fake" + "code.cloudfoundry.org/cli/util/configv3" ) var _ = Describe("cf logout", func() { BeforeEach(func() { helpers.SetConfig(func(config *configv3.Config) { config.ConfigFile.CFOnK8s.Enabled = true - config.ConfigFile.CFOnK8s.AuthInfo = "something" + config.ConfigFile.CFOnK8s.AuthInfo = "my-user" }) + + apiServer.SetConfiguration(fake.CFAPIConfig{Routes: map[string]fake.Response{ + "GET /whoami": { + Code: http.StatusOK, Body: map[string]interface{}{ + "name": "my-user", + "kind": "User", + }, + }, + }}) + + kubeConfig := apiv1.Config{ + Kind: "Config", + APIVersion: "v1", + AuthInfos: []apiv1.NamedAuthInfo{ + { + Name: "my-user", + AuthInfo: apiv1.AuthInfo{ + AuthProvider: &apiv1.AuthProviderConfig{ + Name: "oidc", + Config: map[string]string{ + "id-token": string(token), + "idp-issuer-url": "-", + "client-id": "-", + }, + }, + }, + }, + }, + Clusters: []apiv1.NamedCluster{ + { + Name: "my-cluster", + Cluster: apiv1.Cluster{ + Server: "https://example.org", + }, + }, + }, + Contexts: []apiv1.NamedContext{ + { + Name: "my-context", + Context: apiv1.Context{ + Cluster: "my-cluster", + AuthInfo: "my-auth-info", + Namespace: "my-namespace", + }, + }, + }, + CurrentContext: "my-context", + } + + kubeConfigPath := filepath.Join(homeDir, ".kube", "config") + storeKubeConfig(kubeConfig, kubeConfigPath) + + env = helpers.CFEnv{ + EnvVars: map[string]string{ + "KUBECONFIG": kubeConfigPath, + }, + } }) JustBeforeEach(func() { - Eventually(helpers.CF("logout")).Should(gexec.Exit(0)) + Eventually(helpers.CustomCF(env, "logout")).Should(gexec.Exit(0)) }) It("clears the auth-info", func() { From 504d4e86a5be28f6868ed08894cc267be03c5ffb Mon Sep 17 00:00:00 2001 From: Matt Royal Date: Wed, 16 Mar 2022 16:32:08 -0700 Subject: [PATCH 025/248] Send Authorization header for logcache on CFonK8s - Extract "Authorization" header logic for CFonK8s into api/shared/WrapForCFOnK8sAuth and refactor existing code to use this - Move LogCache client into api/logcache to avoid a cyclic import - Bubble out error from logcache.NewClient - New selfcontained tests for logcache request changes Co-authored-by: Matt Royal Co-authored-by: Dave Walter Co-authored-by: Ashwin Krishna --- .../wrapper/kubernetes_authentication.go | 98 +--- .../wrapper/kubernetes_authentication_test.go | 2 +- {command => api/logcache}/log_cache_client.go | 56 ++- api/shared/shared_suite_test.go | 25 + api/shared/sharedfakes/fake_round_tripper.go | 114 +++++ api/shared/wrap_for_cf_on_k8s.go | 124 +++++ api/shared/wrap_for_cf_on_k8s_test.go | 462 ++++++++++++++++++ cf/api/repository_locator.go | 9 +- command/v7/copy_source_command.go | 8 +- command/v7/logs_command.go | 6 +- command/v7/push_command.go | 13 +- command/v7/restage_command.go | 8 +- command/v7/restart_command.go | 9 +- command/v7/stage_package_command.go | 7 +- command/v7/start_command.go | 8 +- .../selfcontained/kubernetes_auth_log_test.go | 138 ++++++ 16 files changed, 967 insertions(+), 120 deletions(-) rename {command => api/logcache}/log_cache_client.go (76%) create mode 100644 api/shared/shared_suite_test.go create mode 100644 api/shared/sharedfakes/fake_round_tripper.go create mode 100644 api/shared/wrap_for_cf_on_k8s.go create mode 100644 api/shared/wrap_for_cf_on_k8s_test.go create mode 100644 integration/v7/selfcontained/kubernetes_auth_log_test.go diff --git a/api/cloudcontroller/wrapper/kubernetes_authentication.go b/api/cloudcontroller/wrapper/kubernetes_authentication.go index b683278077e..622bd580ccf 100644 --- a/api/cloudcontroller/wrapper/kubernetes_authentication.go +++ b/api/cloudcontroller/wrapper/kubernetes_authentication.go @@ -1,25 +1,12 @@ package wrapper import ( - "bytes" - "crypto/x509" - "encoding/base64" - "encoding/pem" - "errors" - "fmt" "net/http" "code.cloudfoundry.org/cli/actor/v7action" "code.cloudfoundry.org/cli/api/cloudcontroller" + "code.cloudfoundry.org/cli/api/shared" "code.cloudfoundry.org/cli/command" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" - "k8s.io/client-go/tools/clientcmd/api" - "k8s.io/client-go/transport" - - _ "k8s.io/client-go/plugin/pkg/client/auth/azure" - _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" - _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" ) type KubernetesAuthentication struct { @@ -40,87 +27,16 @@ func NewKubernetesAuthentication( } func (a *KubernetesAuthentication) Make(request *cloudcontroller.Request, passedResponse *cloudcontroller.Response) error { - username, err := a.config.CurrentUserName() + roundTripper, err := shared.WrapForCFOnK8sAuth(a.config, a.k8sConfigGetter, connectionRoundTripper{ + connection: a.connection, + ccRequest: request, + ccResponse: passedResponse, + }) if err != nil { return err } - if username == "" { - return errors.New("current user not set") - } - - k8sConfig, err := a.k8sConfigGetter.Get() - if err != nil { - return err - } - - restConfig, err := clientcmd.NewDefaultClientConfig( - *k8sConfig, - &clientcmd.ConfigOverrides{ - Context: api.Context{AuthInfo: username}, - }).ClientConfig() - if err != nil { - return err - } - - tlsConfig, err := rest.TLSConfigFor(restConfig) - if err != nil { - return fmt.Errorf("failed to get tls config: %w", err) - } - - if tlsConfig != nil && tlsConfig.GetClientCertificate != nil { - cert, err := tlsConfig.GetClientCertificate(nil) - if err != nil { - return fmt.Errorf("failed to get client certificate: %w", err) - } - - if len(cert.Certificate) > 0 && cert.PrivateKey != nil { - var buf bytes.Buffer - - if err := pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Certificate[0]}); err != nil { - return fmt.Errorf("could not convert certificate to PEM format: %w", err) - } - - key, err := x509.MarshalPKCS8PrivateKey(cert.PrivateKey) - if err != nil { - return fmt.Errorf("could not marshal private key: %w", err) - } - - if err := pem.Encode(&buf, &pem.Block{Type: "PRIVATE KEY", Bytes: key}); err != nil { - return fmt.Errorf("could not convert key to PEM format: %w", err) - } - - auth := "ClientCert " + base64.StdEncoding.EncodeToString(buf.Bytes()) - request.Header.Set("Authorization", auth) - - return a.connection.Make(request, passedResponse) - } - } - - transportConfig, err := restConfig.TransportConfig() - if err != nil { - return fmt.Errorf("failed to get transport config: %w", err) - } - - var roundtripper http.RoundTripper - if transportConfig.WrapTransport == nil { - // i.e. not auth-provider or exec plugin - roundtripper, err = transport.HTTPWrappersForConfig(transportConfig, connectionRoundTripper{ - connection: a.connection, - ccRequest: request, - ccResponse: passedResponse, - }) - if err != nil { - return fmt.Errorf("failed to create new transport: %w", err) - } - } else { - roundtripper = transportConfig.WrapTransport(connectionRoundTripper{ - connection: a.connection, - ccRequest: request, - ccResponse: passedResponse, - }) - } - _, err = roundtripper.RoundTrip(request.Request) + _, err = roundTripper.RoundTrip(request.Request) return err } diff --git a/api/cloudcontroller/wrapper/kubernetes_authentication_test.go b/api/cloudcontroller/wrapper/kubernetes_authentication_test.go index e46a282438e..b6c9fc3fb3f 100644 --- a/api/cloudcontroller/wrapper/kubernetes_authentication_test.go +++ b/api/cloudcontroller/wrapper/kubernetes_authentication_test.go @@ -119,7 +119,7 @@ var _ = Describe("KubernetesAuthentication", func() { }) }) - When("the chosen kubeernetes auth info is not present in kubeconfig", func() { + When("the chosen kubernetes auth info is not present in kubeconfig", func() { BeforeEach(func() { config.CurrentUserNameReturns("not-present", nil) }) diff --git a/command/log_cache_client.go b/api/logcache/log_cache_client.go similarity index 76% rename from command/log_cache_client.go rename to api/logcache/log_cache_client.go index f6884818225..c8bdc935954 100644 --- a/command/log_cache_client.go +++ b/api/logcache/log_cache_client.go @@ -1,4 +1,4 @@ -package command +package logcache import ( "fmt" @@ -8,8 +8,12 @@ import ( "strings" "time" - "code.cloudfoundry.org/cli/util" logcache "code.cloudfoundry.org/go-log-cache" + + "code.cloudfoundry.org/cli/actor/v7action" + "code.cloudfoundry.org/cli/api/shared" + "code.cloudfoundry.org/cli/command" + "code.cloudfoundry.org/cli/util" ) type RequestLoggerOutput interface { @@ -62,15 +66,23 @@ func (p *DebugPrinter) addOutput(output RequestLoggerOutput) { p.outputs = append(p.outputs, output) } +type userAgentHTTPClient struct { + c logcache.HTTPClient + userAgent string +} + +func (c *userAgentHTTPClient) Do(req *http.Request) (*http.Response, error) { + req.Header.Set("User-Agent", c.userAgent) + return c.c.Do(req) +} + type tokenHTTPClient struct { c logcache.HTTPClient accessToken func() string - userAgent string } func (c *tokenHTTPClient) Do(req *http.Request) (*http.Response, error) { req.Header.Set("Authorization", c.accessToken()) - req.Header.Set("User-Agent", c.userAgent) return c.c.Do(req) } @@ -93,9 +105,9 @@ func (c *httpDebugClient) Do(req *http.Request) (*http.Response, error) { return resp, err } -// NewLogCacheClient returns back a configured Log Cache Client. -func NewLogCacheClient(logCacheEndpoint string, config Config, ui UI) *logcache.Client { - tr := &http.Transport{ +// NewClient returns back a configured Log Cache Client. +func NewClient(logCacheEndpoint string, config command.Config, ui command.UI, k8sConfigGetter v7action.KubernetesConfigGetter) (*logcache.Client, error) { + var tr http.RoundTripper = &http.Transport{ Proxy: http.ProxyFromEnvironment, TLSClientConfig: util.NewTLSConfig(nil, config.SkipSSLValidation()), DialContext: (&net.Dialer{ @@ -104,8 +116,19 @@ func NewLogCacheClient(logCacheEndpoint string, config Config, ui UI) *logcache. }).DialContext, } + if config.IsCFOnK8s() { + var err error + tr, err = shared.WrapForCFOnK8sAuth(config, k8sConfigGetter, tr) + if err != nil { + return nil, err + } + } + var client logcache.HTTPClient //nolint - client = &http.Client{Transport: tr} + client = &userAgentHTTPClient{ + c: &http.Client{Transport: tr}, + userAgent: fmt.Sprintf("%s/%s (%s; %s %s)", config.BinaryName(), config.BinaryVersion(), runtime.Version(), runtime.GOARCH, runtime.GOOS), + } verbose, location := config.Verbose() if verbose && ui != nil { @@ -118,16 +141,19 @@ func NewLogCacheClient(logCacheEndpoint string, config Config, ui UI) *logcache. client = &httpDebugClient{printer: printer, c: client} } - userAgent := fmt.Sprintf("%s/%s (%s; %s %s)", config.BinaryName(), config.BinaryVersion(), runtime.Version(), runtime.GOARCH, runtime.GOOS) - return logcache.NewClient( - logCacheEndpoint, - logcache.WithHTTPClient(&tokenHTTPClient{ + if !config.IsCFOnK8s() { + client = &tokenHTTPClient{ c: client, accessToken: config.AccessToken, - userAgent: userAgent, - }), - ) + } + } + + return logcache.NewClient( + logCacheEndpoint, + logcache.WithHTTPClient(client), + ), nil } + func headersString(header http.Header) string { var result string for name, values := range header { diff --git a/api/shared/shared_suite_test.go b/api/shared/shared_suite_test.go new file mode 100644 index 00000000000..bc69c85df0f --- /dev/null +++ b/api/shared/shared_suite_test.go @@ -0,0 +1,25 @@ +package shared_test + +import ( + "crypto/rand" + "crypto/rsa" + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestShared(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Shared Wrapper Suite") +} + +var ( + keyPair *rsa.PrivateKey +) + +var _ = BeforeEach(func() { + var err error + keyPair, err = rsa.GenerateKey(rand.Reader, 2048) + Expect(err).NotTo(HaveOccurred()) +}) diff --git a/api/shared/sharedfakes/fake_round_tripper.go b/api/shared/sharedfakes/fake_round_tripper.go new file mode 100644 index 00000000000..02f1ff17922 --- /dev/null +++ b/api/shared/sharedfakes/fake_round_tripper.go @@ -0,0 +1,114 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package sharedfakes + +import ( + "net/http" + "sync" +) + +type FakeRoundTripper struct { + RoundTripStub func(*http.Request) (*http.Response, error) + roundTripMutex sync.RWMutex + roundTripArgsForCall []struct { + arg1 *http.Request + } + roundTripReturns struct { + result1 *http.Response + result2 error + } + roundTripReturnsOnCall map[int]struct { + result1 *http.Response + result2 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeRoundTripper) RoundTrip(arg1 *http.Request) (*http.Response, error) { + fake.roundTripMutex.Lock() + ret, specificReturn := fake.roundTripReturnsOnCall[len(fake.roundTripArgsForCall)] + fake.roundTripArgsForCall = append(fake.roundTripArgsForCall, struct { + arg1 *http.Request + }{arg1}) + fake.recordInvocation("RoundTrip", []interface{}{arg1}) + fake.roundTripMutex.Unlock() + if fake.RoundTripStub != nil { + return fake.RoundTripStub(arg1) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.roundTripReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeRoundTripper) RoundTripCallCount() int { + fake.roundTripMutex.RLock() + defer fake.roundTripMutex.RUnlock() + return len(fake.roundTripArgsForCall) +} + +func (fake *FakeRoundTripper) RoundTripCalls(stub func(*http.Request) (*http.Response, error)) { + fake.roundTripMutex.Lock() + defer fake.roundTripMutex.Unlock() + fake.RoundTripStub = stub +} + +func (fake *FakeRoundTripper) RoundTripArgsForCall(i int) *http.Request { + fake.roundTripMutex.RLock() + defer fake.roundTripMutex.RUnlock() + argsForCall := fake.roundTripArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeRoundTripper) RoundTripReturns(result1 *http.Response, result2 error) { + fake.roundTripMutex.Lock() + defer fake.roundTripMutex.Unlock() + fake.RoundTripStub = nil + fake.roundTripReturns = struct { + result1 *http.Response + result2 error + }{result1, result2} +} + +func (fake *FakeRoundTripper) RoundTripReturnsOnCall(i int, result1 *http.Response, result2 error) { + fake.roundTripMutex.Lock() + defer fake.roundTripMutex.Unlock() + fake.RoundTripStub = nil + if fake.roundTripReturnsOnCall == nil { + fake.roundTripReturnsOnCall = make(map[int]struct { + result1 *http.Response + result2 error + }) + } + fake.roundTripReturnsOnCall[i] = struct { + result1 *http.Response + result2 error + }{result1, result2} +} + +func (fake *FakeRoundTripper) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.roundTripMutex.RLock() + defer fake.roundTripMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeRoundTripper) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ http.RoundTripper = new(FakeRoundTripper) diff --git a/api/shared/wrap_for_cf_on_k8s.go b/api/shared/wrap_for_cf_on_k8s.go new file mode 100644 index 00000000000..d5734d6ffd5 --- /dev/null +++ b/api/shared/wrap_for_cf_on_k8s.go @@ -0,0 +1,124 @@ +package shared + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "net/http" + + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/tools/clientcmd/api" + "k8s.io/client-go/transport" + + "code.cloudfoundry.org/cli/actor/v7action" + "code.cloudfoundry.org/cli/command" + + // imported for the side effects + _ "k8s.io/client-go/plugin/pkg/client/auth/azure" + _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" + _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" +) + +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 net/http.RoundTripper + +func WrapForCFOnK8sAuth(config command.Config, k8sConfigGetter v7action.KubernetesConfigGetter, roundTripper http.RoundTripper) (http.RoundTripper, error) { + username, err := config.CurrentUserName() + if err != nil { + return nil, err + } + if username == "" { + return nil, errors.New("current user not set") + } + + k8sConfig, err := k8sConfigGetter.Get() + if err != nil { + return nil, err + } + + restConfig, err := clientcmd.NewDefaultClientConfig( + *k8sConfig, + &clientcmd.ConfigOverrides{ + Context: api.Context{AuthInfo: username}, + }, + ).ClientConfig() + if err != nil { + return nil, err + } + + // Special case for certs, since we don't want mtls + cert, err := getCert(restConfig) + if err != nil { + return nil, err + } + + transportConfig, err := restConfig.TransportConfig() + if err != nil { + return nil, fmt.Errorf("failed to get transport config: %w", err) + } + + if cert != nil { + return certRoundTripper{ + cert: cert, + roundTripper: roundTripper, + }, nil + } + + if transportConfig.WrapTransport == nil { + // i.e. not auth-provider or exec plugin + return transport.HTTPWrappersForConfig(transportConfig, roundTripper) + } + + // using auth provider to generate token + return transportConfig.WrapTransport(roundTripper), nil +} + +func getCert(restConfig *rest.Config) (*tls.Certificate, error) { + tlsConfig, err := rest.TLSConfigFor(restConfig) + if err != nil { + return nil, fmt.Errorf("failed to get tls config: %w", err) + } + + if tlsConfig != nil && tlsConfig.GetClientCertificate != nil { + cert, err := tlsConfig.GetClientCertificate(nil) + if err != nil { + return nil, fmt.Errorf("failed to get client certificate: %w", err) + } + + if len(cert.Certificate) > 0 && cert.PrivateKey != nil { + return cert, nil + } + } + return nil, nil +} + +type certRoundTripper struct { + cert *tls.Certificate + roundTripper http.RoundTripper +} + +func (rt certRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + var buf bytes.Buffer + + if err := pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: rt.cert.Certificate[0]}); err != nil { + return nil, fmt.Errorf("could not convert certificate to PEM format: %w", err) + } + + key, err := x509.MarshalPKCS8PrivateKey(rt.cert.PrivateKey) + if err != nil { + return nil, fmt.Errorf("could not marshal private key: %w", err) + } + + if err := pem.Encode(&buf, &pem.Block{Type: "PRIVATE KEY", Bytes: key}); err != nil { + return nil, fmt.Errorf("could not convert key to PEM format: %w", err) + } + + auth := "ClientCert " + base64.StdEncoding.EncodeToString(buf.Bytes()) + req.Header.Set("Authorization", auth) + + return rt.roundTripper.RoundTrip(req) +} diff --git a/api/shared/wrap_for_cf_on_k8s_test.go b/api/shared/wrap_for_cf_on_k8s_test.go new file mode 100644 index 00000000000..a0c79c89ebd --- /dev/null +++ b/api/shared/wrap_for_cf_on_k8s_test.go @@ -0,0 +1,462 @@ +package shared_test + +import ( + "encoding/base64" + "encoding/json" + "encoding/pem" + "errors" + "io/ioutil" + "net/http" + "os" + "strings" + "time" + + "code.cloudfoundry.org/cli/actor/v7action/v7actionfakes" + "code.cloudfoundry.org/cli/api/shared" + "code.cloudfoundry.org/cli/api/shared/sharedfakes" + "code.cloudfoundry.org/cli/command/commandfakes" + + "github.com/SermoDigital/jose/crypto" + "github.com/SermoDigital/jose/jws" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1" + "k8s.io/client-go/tools/clientcmd/api" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +const ( + clientCertData = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURJVENDQWdtZ0F3SUJBZ0lJVk9iMUFIckxNUjh3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TVRFd01EVXhOVEExTURsYUZ3MHlNakV3TURVeE5UQTFNVEZhTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXJrdWxLbS9qTTJhZWZsdjkKK00zQk9Jc2QvVXZrRTBONGhWb3hSeWRBbE0xQXhWd3REYUdzL3dmUzRzb0xuNHJENTF3UE1SRlNJaitwSzdGYQprRGdaR0x4UFhrai96UkZOTzcvU3J2RHYwVGxjYjJENzNCS21qaXArQ2hBWkpQdWhMQlY2VnlTN0pXSWhOM1lOCktyamR5TnB5MHN3SjI1TW9CbW1saUpFc3V2dCtDaEhseERqWE9KenF1U2owa1hPQVVsWUFTN1dKK09JMU9HbzQKUjcvdHdHZlFTNW9oYXpRVVlDR2lZSllYcjVRNkVKTmJOVVI0RjdpRSthY1I5Rm9GNnNKSmkrQStET1VDUFFSKwptbjQ5Zm1pcFVHSGtMc3BicTNFZ0FEME40VW5jcmIyeUJEMFNVTmdLQmJjclY1S2hybFA2SzkwNkY5NEpubzNHCm1Id1JwUUlEQVFBQm8xWXdWREFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RBWURWUjBUQVFIL0JBSXdBREFmQmdOVkhTTUVHREFXZ0JUV2VNZ1ZBRkRhbWcraDRqS3hoRUh2Q1l5egp5akFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBUUxMWWFXQTRva1M2b3ZEWjQ1Z28ybkVZdUR4MklmRXZwYnh3CkNmYkFTNDY4M3lLT3FiYVBHOEpTVGhSbkh3TWlMcVBrbGFsdkJvV2R3aFB5Vkk0d2tVNHI4Y2c0UEpxNEZwWnQKVkNUQzFPZWVwRGpTMFpVQjRwSDVIZVlNQUxqSDBqcFV3RU96djFpaEtid05IMHFoZ2pGeUNTdld5TG9oZHdzbApJWXIvV1NEZm50NlBETC84TjFpcEJJbEN5Z1JHVGdoSFhPemhHUklPWG4rYWVOR29yWm9YWm0xbHErc1hyUnc5CktNdVZhRmdhaWVjSm0vbytyemFFSG9VZjRYOERKeVNubmVTa3ViaEx6ZERNc2o5eEs1cEJpdFgvaDlQMUQrMkcKeW5rcWdJVTJSWTM0SjBRcnU4Z0syNlJVT2pOcHIvRWJHQ0dUQUxiMXJnSDM0K2NFdlE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" + clientKeyData = "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2Z0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktnd2dnU2tBZ0VBQW9JQkFRQ3VTNlVxYitNelpwNSsKVy8zNHpjRTRpeDM5UytRVFEzaUZXakZISjBDVXpVREZYQzBOb2F6L0I5TGl5Z3VmaXNQblhBOHhFVklpUDZrcgpzVnFRT0JrWXZFOWVTUC9ORVUwN3Y5S3U4Ty9ST1Z4dllQdmNFcWFPS240S0VCa2srNkVzRlhwWEpMc2xZaUUzCmRnMHF1TjNJMm5MU3pBbmJreWdHYWFXSWtTeTYrMzRLRWVYRU9OYzRuT3E1S1BTUmM0QlNWZ0JMdFluNDRqVTQKYWpoSHYrM0FaOUJMbWlGck5CUmdJYUpnbGhldmxEb1FrMXMxUkhnWHVJVDVweEgwV2dYcXdrbUw0RDRNNVFJOQpCSDZhZmoxK2FLbFFZZVF1eWx1cmNTQUFQUTNoU2R5dHZiSUVQUkpRMkFvRnR5dFhrcUd1VS9vcjNUb1gzZ21lCmpjYVlmQkdsQWdNQkFBRUNnZ0VBZG80WndLM3VteTM0TFBjaDM3VUU4eE1keVFkd0VmSlk3a3dWTE5MMFNNTDgKaGNKWEd1aVlKYmtLcHh6TG55L2laV0xuS25jZnFSQW9ZQUg1R2hRdWJmYlkvY2NseURVMmxhZTdCU2Y1MkJUdQpYUXhaQks3aS85ekRjdERVYWFXSFVkY2lLbGhmdStQdHVDM2ljdWJnWlJqQjljUzRCOVVtNm9XK0JSREtuandICkduQ0lEZlNNQWt4VXdTaUwwa2NXelNpZ1BYMVN3UHcxOEZvZWgzTmJEd1VXTHhxUWZLVThydVlSTUsxYUg5M3cKcjFtbjlDWUwvd0hiVWRqcmtZMlIxTjVUR21ab2Vldm5qUXgyQVc2NkYzdEg1cGg4RTF6TEFQVTl4TFdRTW9KcwpXM0gzSTdUaEYvRnJuNERQa3hQbThUUVVhQUdvQ09SSWFUQkN5VlgxQVFLQmdRREkxbkRmNWYySHdHaldrTStpCk9YbGE1R1VnRUtXaGZpeGhidE5OclNpMDU5VnZQUEJwNXdtbGQzMHJKUDhWem8vbnFnUW5ISmpmaEQ2Y3NSMTQKL2VlMHZ1Um0zYzZwZzMrODdwOHhWY3lLNHhDd0JmdFFuMGRZWWFLMkRMOEtYb0liYThpN09EQmFoNW5OZWQwcgpKa1RPcE5NRGRkL0p0bEpPZ25jRXBlUk9oUUtCZ1FEZUt1L0R1MXU1QVR3Y3p5STRXOWV1L1YwTXRwMHdqM3RpClF2MmpObW83QU1zS3BwK0ZKVDFqWFhUKzZCTm02OWpxUVJwdlAyd2RhVUdqV1dLa1lHVEVpbUZCc2ZuKzJDOFAKOEc3Uk50YWpRdEV2QlR1ZDZPN0tZUkFoTU56dm9RcDkrZmJKY1ZsRG13Nlk0bUYzUTJXS3NmZU51TGtpY3VqNQpYVFV1ekVMd29RS0JnUUREU0IvQTFYVEx4cjhwd3V6aHBGam5sQ1R3Skwrb1kzTHIya01EeUZkSWNCUU1jWWlpCnNNK2tZS2NJaUpTdnM0WWhrQ014bEpEZzVVbXNPbHVhQmVpQ3l3cHpLMEdEZWlWK285ZU90UXFLRVhkc2NLU0oKSkJiUFRVQlZHOWUyVVdiWkd0aTNrazhSOThBSkYzR0NQMWV3Um53WFpVb1FiSU5qYTJBbTJOZEJzUUtCZ0Q4eApOVXVXTWl1NE56SDJsTVExRTI4NXI4cmE4bkVLanN6UFF6ZTJWWmI4emNQMHl2RGpPOGZVb0YrVkFWZklBOFgxCnlLQVdDUm1BZytRRG03UW5tdUh3Zm1OaVRUcDRvVUpHWUM3d0N6TWE0VWNmbE9xQWc5TmFzbXpPYWpsYXRCSkwKRkRBT0pwYTlOdlN6aDRlVnl2OGRTYzJzMmpQN1BWc1ljUFVqc25LaEFvR0JBSy9kQjlnVEFpME5nczVmaVNtWQovWkp3Yk52MjcyTHdKbWV4Vit2eWtjN3J5LzRraTRQb2xRd1BHNzQ5eFZ0T2NNc2FhRlVNMVVkclN2NlIwbjlkCmpTbXhCeTl2YWdzc1FmVDNSc3BvUUJKM0w5YWxiNHM2V2ZtUEpzNkFrQkhIZHNpVXFaaElYT2J2WE1lQ0k2aVMKOTQ2R0toekFxMlVGbjhFUGxXaFVNeEFiCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K" +) + +var _ = Describe("WrapForCFOnK8sAuth", func() { + var ( + config *commandfakes.FakeConfig + k8sConfigGetter *v7actionfakes.FakeKubernetesConfigGetter + req *http.Request + res *http.Response + actualRes *http.Response + kubeConfig *api.Config + wrapErr error + wrappedRoundTripper *sharedfakes.FakeRoundTripper + ) + + BeforeEach(func() { + kubeConfig = &api.Config{ + Kind: "Config", + APIVersion: "v1", + Clusters: map[string]*api.Cluster{ + "my-cluster": { + Server: "https://example.org", + }, + }, + Contexts: map[string]*api.Context{ + "my-context": { + Cluster: "my-cluster", + AuthInfo: "my-auth-info", + Namespace: "my-namespace", + }, + }, + CurrentContext: "my-context", + AuthInfos: map[string]*api.AuthInfo{}, + } + + k8sConfigGetter = new(v7actionfakes.FakeKubernetesConfigGetter) + k8sConfigGetter.GetReturns(kubeConfig, nil) + + config = new(commandfakes.FakeConfig) + config.CurrentUserNameReturns("auth-test", nil) + + var err error + req, err = http.NewRequest(http.MethodPost, "", strings.NewReader("hello")) + Expect(err).NotTo(HaveOccurred()) + + wrappedRoundTripper = new(sharedfakes.FakeRoundTripper) + res = &http.Response{StatusCode: http.StatusTeapot} + + wrappedRoundTripper.RoundTripReturns(res, nil) + actualRes = nil + }) + + JustBeforeEach(func() { + var roundTripper http.RoundTripper + roundTripper, wrapErr = shared.WrapForCFOnK8sAuth(config, k8sConfigGetter, wrappedRoundTripper) + + if wrapErr == nil { + actualRes, wrapErr = roundTripper.RoundTrip(req) + } + }) + + When("getting the k8s config fails", func() { + BeforeEach(func() { + k8sConfigGetter.GetReturns(nil, errors.New("boom!")) + }) + + It("returns the error", func() { + Expect(wrapErr).To(MatchError("boom!")) + }) + }) + + When("no user is set in the config", func() { + BeforeEach(func() { + config.CurrentUserNameReturns("", nil) + }) + + It("errors", func() { + Expect(wrapErr).To(MatchError(ContainSubstring("current user not set"))) + }) + }) + + When("there is an error getting the current user from the config", func() { + BeforeEach(func() { + config.CurrentUserNameReturns("", errors.New("boom")) + }) + + It("errors", func() { + Expect(wrapErr).To(MatchError(ContainSubstring("boom"))) + }) + }) + + When("the chosen kubernetes auth info is not present in kubeconfig", func() { + BeforeEach(func() { + config.CurrentUserNameReturns("not-present", nil) + }) + + It("errors", func() { + Expect(wrapErr).To(MatchError(ContainSubstring(`auth info "not-present" does not exist`))) + }) + }) + + checkCalls := func() *http.Request { + Expect(wrapErr).NotTo(HaveOccurred()) + Expect(wrappedRoundTripper.RoundTripCallCount()).To(Equal(1)) + + actualReq := wrappedRoundTripper.RoundTripArgsForCall(0) + + body, err := ioutil.ReadAll(actualReq.Body) + Expect(err).NotTo(HaveOccurred()) + Expect(string(body)).To(Equal("hello")) + + Expect(actualRes).To(Equal(res)) + + return actualReq + } + + checkBearerTokenInAuthHeader := func() { + actualReq := checkCalls() + + token, err := jws.ParseJWTFromRequest(actualReq) + Expect(err).NotTo(HaveOccurred()) + Expect(token.Validate(keyPair.Public(), crypto.SigningMethodRS256)).To(Succeed()) + + claims := token.Claims() + Expect(claims).To(HaveKeyWithValue("another", "thing")) + } + + checkClientCertInAuthHeader := func() { + actualReq := checkCalls() + + Expect(actualReq.Header).To(HaveKeyWithValue("Authorization", ConsistOf(HavePrefix("ClientCert ")))) + + certAndKeyPEMBase64 := actualReq.Header.Get("Authorization")[11:] + certAndKeyPEM, err := base64.StdEncoding.DecodeString(certAndKeyPEMBase64) + Expect(err).NotTo(HaveOccurred()) + + cert, rest := pem.Decode(certAndKeyPEM) + Expect(cert.Type).To(Equal(pemDecodeKubeConfigCertData(clientCertData).Type)) + Expect(cert.Bytes).To(Equal(pemDecodeKubeConfigCertData(clientCertData).Bytes)) + + var key *pem.Block + key, rest = pem.Decode(rest) + Expect(key.Bytes).To(Equal(pemDecodeKubeConfigCertData(clientKeyData).Bytes)) + + Expect(rest).To(BeEmpty()) + } + + Describe("auth-provider", func() { + var token []byte + + BeforeEach(func() { + jwt := jws.NewJWT(jws.Claims{ + "exp": time.Now().Add(time.Hour).Unix(), + "another": "thing", + }, crypto.SigningMethodRS256) + var err error + token, err = jwt.Serialize(keyPair) + Expect(err).NotTo(HaveOccurred()) + + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + AuthProvider: &api.AuthProviderConfig{ + Name: "oidc", + Config: map[string]string{ + "id-token": string(token), + "idp-issuer-url": "-", + "client-id": "-", + }, + }, + } + }) + + It("uses the auth-provider to generate the Bearer token", func() { + checkBearerTokenInAuthHeader() + }) + }) + + Describe("client certs", func() { + var ( + certFilePath string + keyFilePath string + ) + + BeforeEach(func() { + certFilePath = writeToFile(clientCertData) + keyFilePath = writeToFile(clientKeyData) + }) + + AfterEach(func() { + Expect(os.RemoveAll(certFilePath)).To(Succeed()) + Expect(os.RemoveAll(keyFilePath)).To(Succeed()) + }) + + When("inline cert and key are provided", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + ClientCertificateData: []byte(base64Decode(clientCertData)), + ClientKeyData: []byte(base64Decode(clientKeyData)), + } + }) + + It("puts concatenated client ceritificate and key data into the Authorization header", func() { + checkClientCertInAuthHeader() + }) + }) + + When("cert and key are provided in files", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + ClientCertificate: certFilePath, + ClientKey: keyFilePath, + } + }) + + It("puts concatenated client ceritificate and key data into the Authorization header", func() { + checkClientCertInAuthHeader() + }) + + When("cert file cannot be read", func() { + BeforeEach(func() { + Expect(os.Remove(certFilePath)).To(Succeed()) + }) + + It("returns an error", func() { + Expect(wrapErr).To(MatchError(ContainSubstring(certFilePath))) + }) + }) + + When("key file cannot be read", func() { + BeforeEach(func() { + Expect(os.Remove(keyFilePath)).To(Succeed()) + }) + + It("returns an error", func() { + Expect(wrapErr).To(MatchError(ContainSubstring(keyFilePath))) + }) + }) + }) + + When("file and inline cert is provided", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + ClientCertificate: certFilePath, + ClientCertificateData: []byte(base64Decode(clientCertData)), + ClientKeyData: []byte(base64Decode(clientKeyData)), + } + }) + + It("complains about invalid configuration", func() { + Expect(wrapErr).To(MatchError(ContainSubstring("client-cert-data and client-cert are both specified"))) + }) + }) + + When("file and inline key is provided", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + ClientCertificateData: []byte(base64Decode(clientCertData)), + ClientKeyData: []byte(base64Decode(clientKeyData)), + ClientKey: keyFilePath, + } + }) + + It("complains about invalid configuration", func() { + Expect(wrapErr).To(MatchError(ContainSubstring("client-key-data and client-key are both specified"))) + }) + }) + + When("inline cert and key file are provided", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + ClientCertificateData: []byte(base64Decode(clientCertData)), + ClientKey: keyFilePath, + } + }) + + It("uses the inline key", func() { + checkClientCertInAuthHeader() + }) + }) + + When("cert file and inline key are provided", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + ClientCertificate: certFilePath, + ClientKeyData: []byte(base64Decode(clientKeyData)), + } + }) + + It("uses the inline key", func() { + checkClientCertInAuthHeader() + }) + }) + }) + + Describe("exec", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + Exec: &api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1beta1", + InteractiveMode: "Never", + Command: "echo", + }, + } + }) + + When("the command returns a token", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"].Exec.Args = []string{execCredential(&clientauthenticationv1beta1.ExecCredentialStatus{ + Token: "a-token", + })} + }) + + It("uses the exec command to generate the Bearer token", func() { + Expect(wrapErr).NotTo(HaveOccurred()) + Expect(wrappedRoundTripper.RoundTripCallCount()).To(Equal(1)) + + actualReq := wrappedRoundTripper.RoundTripArgsForCall(0) + Expect(actualReq.Header.Get("Authorization")).To(Equal("Bearer a-token")) + + Expect(actualRes).To(Equal(res)) + }) + }) + + When("the command returns a client cert and key", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"].Exec.Args = []string{execCredential(&clientauthenticationv1beta1.ExecCredentialStatus{ + ClientCertificateData: base64Decode(clientCertData), + ClientKeyData: base64Decode(clientKeyData), + })} + }) + + It("uses the exec command to generate client certs", func() { + checkClientCertInAuthHeader() + }) + }) + }) + + Describe("tokens provided in config", func() { + var token []byte + + BeforeEach(func() { + jwt := jws.NewJWT(jws.Claims{ + "exp": time.Now().Add(time.Hour).Unix(), + "another": "thing", + }, crypto.SigningMethodRS256) + var err error + token, err = jwt.Serialize(keyPair) + Expect(err).NotTo(HaveOccurred()) + }) + + Context("inline tokens", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + Token: string(token), + } + }) + + It("inserts the token in the authorization header", func() { + checkBearerTokenInAuthHeader() + }) + }) + + Context("token file paths", func() { + var tokenFilePath string + + BeforeEach(func() { + tokenFile, err := ioutil.TempFile("", "") + Expect(err).NotTo(HaveOccurred()) + defer tokenFile.Close() + _, err = tokenFile.Write(token) + Expect(err).NotTo(HaveOccurred()) + tokenFilePath = tokenFile.Name() + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + TokenFile: tokenFilePath, + } + }) + + AfterEach(func() { + Expect(os.RemoveAll(tokenFilePath)).To(Succeed()) + }) + + It("inserts the token in the authorization header", func() { + checkBearerTokenInAuthHeader() + }) + }) + + When("both file and inline token are provided", func() { + BeforeEach(func() { + kubeConfig.AuthInfos["auth-test"] = &api.AuthInfo{ + Token: string(token), + TokenFile: "some-path", + } + }) + + It("the inline token takes precedence", func() { + checkBearerTokenInAuthHeader() + }) + }) + }) +}) + +func pemDecodeKubeConfigCertData(data string) *pem.Block { + decodedData, err := base64.StdEncoding.DecodeString(data) + Expect(err).NotTo(HaveOccurred()) + pemDecodedBlock, rest := pem.Decode(decodedData) + Expect(rest).To(BeEmpty()) + return pemDecodedBlock +} + +func base64Decode(encoded string) string { + decoded, err := base64.StdEncoding.DecodeString(encoded) + Expect(err).NotTo(HaveOccurred()) + return string(decoded) +} + +func writeToFile(base64Data string) string { + file, err := ioutil.TempFile("", "") + Expect(err).NotTo(HaveOccurred()) + file.WriteString(base64Decode(base64Data)) + Expect(file.Close()).To(Succeed()) + return file.Name() +} + +func execCredential(status *clientauthenticationv1beta1.ExecCredentialStatus) string { + execCred, err := json.Marshal(clientauthenticationv1beta1.ExecCredential{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "client.authentication.k8s.io/v1beta1", + }, + Status: status, + }) + Expect(err).NotTo(HaveOccurred()) + return string(execCred) +} diff --git a/cf/api/repository_locator.go b/cf/api/repository_locator.go index ef80f3d7cc7..f0ad31cb1db 100644 --- a/cf/api/repository_locator.go +++ b/cf/api/repository_locator.go @@ -2,6 +2,8 @@ package api import ( "code.cloudfoundry.org/cli/actor/sharedaction" + v7action2 "code.cloudfoundry.org/cli/actor/v7action" + "code.cloudfoundry.org/cli/api/logcache" "code.cloudfoundry.org/cli/cf/api/appevents" api_appfiles "code.cloudfoundry.org/cli/cf/api/appfiles" "code.cloudfoundry.org/cli/cf/api/appinstances" @@ -26,7 +28,6 @@ import ( "code.cloudfoundry.org/cli/cf/configuration/coreconfig" "code.cloudfoundry.org/cli/cf/net" "code.cloudfoundry.org/cli/cf/trace" - "code.cloudfoundry.org/cli/command" "code.cloudfoundry.org/cli/util/configv3" ) @@ -100,7 +101,11 @@ func NewRepositoryLocator(config coreconfig.ReadWriter, gatewaysByName map[strin } logCacheURL := configV3.ConfigFile.LogCacheEndpoint - logCacheClient := command.NewLogCacheClient(logCacheURL, configV3, nil) + logCacheClient, err := logcache.NewClient(logCacheURL, configV3, nil, v7action2.NewDefaultKubernetesConfigGetter()) + if err != nil { + panic("handle this error!") + } + loc.logsRepo = logs.NewLogCacheRepository(logCacheClient, sharedaction.GetRecentLogs, sharedaction.GetStreamingLogs) loc.organizationRepo = organizations.NewCloudControllerOrganizationRepository(config, cloudControllerGateway) diff --git a/command/v7/copy_source_command.go b/command/v7/copy_source_command.go index 42f869b2458..a5c74ae0ea4 100644 --- a/command/v7/copy_source_command.go +++ b/command/v7/copy_source_command.go @@ -1,7 +1,9 @@ package v7 import ( + "code.cloudfoundry.org/cli/actor/v7action" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" + "code.cloudfoundry.org/cli/api/logcache" "code.cloudfoundry.org/cli/command" "code.cloudfoundry.org/cli/command/flag" "code.cloudfoundry.org/cli/command/translatableerror" @@ -55,7 +57,11 @@ func (cmd *CopySourceCommand) Setup(config command.Config, ui command.UI) error return err } - logCacheClient := command.NewLogCacheClient(config.LogCacheEndpoint(), config, ui) + logCacheClient, err := logcache.NewClient(config.LogCacheEndpoint(), config, ui, v7action.NewDefaultKubernetesConfigGetter()) + if err != nil { + return err + } + cmd.Stager = shared.NewAppStager(cmd.Actor, cmd.UI, cmd.Config, logCacheClient) return nil diff --git a/command/v7/logs_command.go b/command/v7/logs_command.go index e5232665010..b2506240752 100644 --- a/command/v7/logs_command.go +++ b/command/v7/logs_command.go @@ -7,6 +7,8 @@ import ( "code.cloudfoundry.org/cli/actor/actionerror" "code.cloudfoundry.org/cli/actor/sharedaction" + "code.cloudfoundry.org/cli/actor/v7action" + "code.cloudfoundry.org/cli/api/logcache" "code.cloudfoundry.org/cli/command" "code.cloudfoundry.org/cli/command/flag" ) @@ -28,8 +30,8 @@ func (cmd *LogsCommand) Setup(config command.Config, ui command.UI) error { return err } - cmd.LogCacheClient = command.NewLogCacheClient(config.LogCacheEndpoint(), config, ui) - return nil + cmd.LogCacheClient, err = logcache.NewClient(config.LogCacheEndpoint(), config, ui, v7action.NewDefaultKubernetesConfigGetter()) + return err } func (cmd LogsCommand) Execute(args []string) error { diff --git a/command/v7/push_command.go b/command/v7/push_command.go index c7becf02fef..ea2e9175e48 100644 --- a/command/v7/push_command.go +++ b/command/v7/push_command.go @@ -6,12 +6,17 @@ import ( "os" "strings" + "github.com/cloudfoundry/bosh-cli/director/template" + log "github.com/sirupsen/logrus" + "gopkg.in/yaml.v2" + "code.cloudfoundry.org/cli/actor/actionerror" "code.cloudfoundry.org/cli/actor/sharedaction" "code.cloudfoundry.org/cli/actor/v7action" "code.cloudfoundry.org/cli/actor/v7pushaction" "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" + "code.cloudfoundry.org/cli/api/logcache" "code.cloudfoundry.org/cli/cf/errors" "code.cloudfoundry.org/cli/command" "code.cloudfoundry.org/cli/command/flag" @@ -21,9 +26,6 @@ import ( "code.cloudfoundry.org/cli/util/configv3" "code.cloudfoundry.org/cli/util/manifestparser" "code.cloudfoundry.org/cli/util/progressbar" - "github.com/cloudfoundry/bosh-cli/director/template" - log "github.com/sirupsen/logrus" - "gopkg.in/yaml.v2" ) //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . ProgressBar @@ -127,7 +129,10 @@ func (cmd *PushCommand) Setup(config command.Config, ui command.UI) error { cmd.VersionActor = cmd.Actor cmd.PushActor = v7pushaction.NewActor(cmd.Actor, sharedaction.NewActor(config)) - cmd.LogCacheClient = command.NewLogCacheClient(config.LogCacheEndpoint(), config, ui) + cmd.LogCacheClient, err = logcache.NewClient(config.LogCacheEndpoint(), config, ui, v7action.NewDefaultKubernetesConfigGetter()) + if err != nil { + return err + } currentDir, err := os.Getwd() cmd.CWD = currentDir diff --git a/command/v7/restage_command.go b/command/v7/restage_command.go index 628bd852130..e9dc01ced53 100644 --- a/command/v7/restage_command.go +++ b/command/v7/restage_command.go @@ -2,7 +2,9 @@ package v7 import ( "code.cloudfoundry.org/cli/actor/actionerror" + "code.cloudfoundry.org/cli/actor/v7action" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" + "code.cloudfoundry.org/cli/api/logcache" "code.cloudfoundry.org/cli/command" "code.cloudfoundry.org/cli/command/flag" "code.cloudfoundry.org/cli/command/translatableerror" @@ -29,7 +31,11 @@ func (cmd *RestageCommand) Setup(config command.Config, ui command.UI) error { return err } - logCacheClient := command.NewLogCacheClient(config.LogCacheEndpoint(), config, ui) + logCacheClient, err := logcache.NewClient(config.LogCacheEndpoint(), config, ui, v7action.NewDefaultKubernetesConfigGetter()) + if err != nil { + return err + } + cmd.Stager = shared.NewAppStager(cmd.Actor, cmd.UI, cmd.Config, logCacheClient) return nil diff --git a/command/v7/restart_command.go b/command/v7/restart_command.go index 66652cc0cf8..71b7774e796 100644 --- a/command/v7/restart_command.go +++ b/command/v7/restart_command.go @@ -1,7 +1,9 @@ package v7 import ( + "code.cloudfoundry.org/cli/actor/v7action" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" + "code.cloudfoundry.org/cli/api/logcache" "code.cloudfoundry.org/cli/command" "code.cloudfoundry.org/cli/command/flag" "code.cloudfoundry.org/cli/command/v7/shared" @@ -26,7 +28,12 @@ func (cmd *RestartCommand) Setup(config command.Config, ui command.UI) error { if err != nil { return err } - logCacheClient := command.NewLogCacheClient(config.LogCacheEndpoint(), config, ui) + + logCacheClient, err := logcache.NewClient(config.LogCacheEndpoint(), config, ui, v7action.NewDefaultKubernetesConfigGetter()) + if err != nil { + return err + } + cmd.Stager = shared.NewAppStager(cmd.Actor, cmd.UI, cmd.Config, logCacheClient) return nil diff --git a/command/v7/stage_package_command.go b/command/v7/stage_package_command.go index 729f497461b..3406a444c33 100644 --- a/command/v7/stage_package_command.go +++ b/command/v7/stage_package_command.go @@ -5,6 +5,8 @@ import ( "time" "code.cloudfoundry.org/cli/actor/sharedaction" + "code.cloudfoundry.org/cli/actor/v7action" + "code.cloudfoundry.org/cli/api/logcache" "code.cloudfoundry.org/cli/command" "code.cloudfoundry.org/cli/command/flag" "code.cloudfoundry.org/cli/command/v7/shared" @@ -30,7 +32,10 @@ func (cmd *StagePackageCommand) Setup(config command.Config, ui command.UI) erro return err } - cmd.LogCacheClient = command.NewLogCacheClient(config.LogCacheEndpoint(), config, ui) + cmd.LogCacheClient, err = logcache.NewClient(config.LogCacheEndpoint(), config, ui, v7action.NewDefaultKubernetesConfigGetter()) + if err != nil { + return err + } return nil } diff --git a/command/v7/start_command.go b/command/v7/start_command.go index 23271215110..823341ff29c 100644 --- a/command/v7/start_command.go +++ b/command/v7/start_command.go @@ -2,7 +2,9 @@ package v7 import ( "code.cloudfoundry.org/cli/actor/sharedaction" + "code.cloudfoundry.org/cli/actor/v7action" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" + "code.cloudfoundry.org/cli/api/logcache" "code.cloudfoundry.org/cli/command" "code.cloudfoundry.org/cli/command/flag" "code.cloudfoundry.org/cli/command/v7/shared" @@ -27,7 +29,11 @@ func (cmd *StartCommand) Setup(config command.Config, ui command.UI) error { return err } - cmd.LogCacheClient = command.NewLogCacheClient(config.LogCacheEndpoint(), config, ui) + cmd.LogCacheClient, err = logcache.NewClient(config.LogCacheEndpoint(), config, ui, v7action.NewDefaultKubernetesConfigGetter()) + if err != nil { + return err + } + cmd.Stager = shared.NewAppStager(cmd.Actor, cmd.UI, cmd.Config, cmd.LogCacheClient) return nil diff --git a/integration/v7/selfcontained/kubernetes_auth_log_test.go b/integration/v7/selfcontained/kubernetes_auth_log_test.go new file mode 100644 index 00000000000..8d2d244c4c3 --- /dev/null +++ b/integration/v7/selfcontained/kubernetes_auth_log_test.go @@ -0,0 +1,138 @@ +package selfcontained_test + +import ( + "net/http" + "path/filepath" + + "code.cloudfoundry.org/cli/integration/helpers" + "code.cloudfoundry.org/cli/integration/v7/selfcontained/fake" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gexec" + apiv1 "k8s.io/client-go/tools/clientcmd/api/v1" + + "code.cloudfoundry.org/cli/util/configv3" +) + +var _ = Describe("logclient auth-provider", func() { + var ( + apiConfig fake.CFAPIConfig + kubeConfig apiv1.Config + ) + + BeforeEach(func() { + apiConfig = fake.CFAPIConfig{ + Routes: map[string]fake.Response{ + "GET /api/v1/read/test-guid": { + Code: http.StatusOK, Body: map[string]interface{}{ + "envelopes": map[string]interface{}{ + "batch": []string{}, + }, + }, + }, + "GET /api/v1/info": { + Code: http.StatusOK, Body: map[string]interface{}{ + "version": "42.1.2", + "vm_uptime": "0", + }, + }, + "GET /v3/apps": { + Code: http.StatusOK, Body: map[string]interface{}{ + "pagination": map[string]interface{}{}, + "resources": []map[string]string{ + { + "guid": "test-guid", + }, + }, + }, + }, + "GET /whoami": { + Code: http.StatusOK, Body: map[string]interface{}{ + "name": "my-user", + "kind": "User", + }, + }, + }, + } + apiServer.SetConfiguration(apiConfig) + helpers.SetConfig(func(config *configv3.Config) { + config.ConfigFile.Target = apiServer.URL() + config.ConfigFile.LogCacheEndpoint = apiServer.URL() + config.ConfigFile.CFOnK8s.Enabled = true + config.ConfigFile.CFOnK8s.AuthInfo = "my-user" + config.ConfigFile.TargetedOrganization = configv3.Organization{ + GUID: "my-org", + Name: "My Org", + } + + config.ConfigFile.TargetedSpace = configv3.Space{ + GUID: "my-space", + Name: "My Space", + } + }) + + kubeConfig = apiv1.Config{ + Kind: "Config", + APIVersion: "v1", + AuthInfos: []apiv1.NamedAuthInfo{ + { + Name: "my-user", + AuthInfo: apiv1.AuthInfo{ + AuthProvider: &apiv1.AuthProviderConfig{ + Name: "oidc", + Config: map[string]string{ + "id-token": string(token), + "idp-issuer-url": "-", + "client-id": "-", + }, + }, + }, + }, + }, + Clusters: []apiv1.NamedCluster{ + { + Name: "my-cluster", + Cluster: apiv1.Cluster{ + Server: "https://example.org", + }, + }, + }, + Contexts: []apiv1.NamedContext{ + { + Name: "my-context", + Context: apiv1.Context{ + Cluster: "my-cluster", + AuthInfo: "my-auth-info", + Namespace: "my-namespace", + }, + }, + }, + CurrentContext: "my-context", + } + kubeConfigPath := filepath.Join(homeDir, ".kube", "config") + storeKubeConfig(kubeConfig, kubeConfigPath) + + env = helpers.CFEnv{ + EnvVars: map[string]string{ + "KUBECONFIG": kubeConfigPath, + }, + } + }) + + JustBeforeEach(func() { + Eventually(helpers.CustomCF(env, "logs", "--recent", "my-test-app")).Should(gexec.Exit(0)) + }) + + It("sends the Bearer token in the Authorization header", func() { + reqs := apiServer.ReceivedRequests()["GET /api/v1/read/test-guid"] + Expect(reqs).To(HaveLen(1)) + Expect(reqs[0].Header).To(HaveKeyWithValue("Authorization", ConsistOf("Bearer "+string(token)))) + }) + + It("sends the User-Agent header", func() { + reqs := apiServer.ReceivedRequests()["GET /api/v1/read/test-guid"] + Expect(reqs).To(HaveLen(1)) + Expect(reqs[0].Header).To(HaveKeyWithValue("User-Agent", ConsistOf(ContainSubstring("cf")))) + }) +}) From 45447b3cbd26fdc36fef40c7f17662f8e1d7aeee Mon Sep 17 00:00:00 2001 From: Matt Royal Date: Fri, 18 Mar 2022 10:56:56 -0700 Subject: [PATCH 026/248] Fix selfcontained tests failing due to /whoami (#2266) Authored-by: Matt Royal --- .../v7/selfcontained/kubernetes_auth_test.go | 20 ++++-- .../v7/selfcontained/login_command_test.go | 17 +++-- .../v7/selfcontained/logout_command_test.go | 71 +++++++++++++++++-- 3 files changed, 93 insertions(+), 15 deletions(-) diff --git a/integration/v7/selfcontained/kubernetes_auth_test.go b/integration/v7/selfcontained/kubernetes_auth_test.go index 113c8e4f175..dfaa8d8bfa0 100644 --- a/integration/v7/selfcontained/kubernetes_auth_test.go +++ b/integration/v7/selfcontained/kubernetes_auth_test.go @@ -4,14 +4,15 @@ import ( "net/http" "path/filepath" - "code.cloudfoundry.org/cli/integration/helpers" - "code.cloudfoundry.org/cli/integration/v7/selfcontained/fake" - "code.cloudfoundry.org/cli/resources" - "code.cloudfoundry.org/cli/util/configv3" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" apiv1 "k8s.io/client-go/tools/clientcmd/api/v1" + + "code.cloudfoundry.org/cli/integration/helpers" + "code.cloudfoundry.org/cli/integration/v7/selfcontained/fake" + "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/configv3" ) var _ = Describe("auth-provider", func() { @@ -29,13 +30,19 @@ var _ = Describe("auth-provider", func() { "resources": []resources.Application{}, }, }, + "GET /whoami": { + Code: http.StatusOK, Body: map[string]interface{}{ + "name": "my-user", + "kind": "User", + }, + }, }, } apiServer.SetConfiguration(apiConfig) helpers.SetConfig(func(config *configv3.Config) { config.ConfigFile.Target = apiServer.URL() config.ConfigFile.CFOnK8s.Enabled = true - config.ConfigFile.CFOnK8s.AuthInfo = "one" + config.ConfigFile.CFOnK8s.AuthInfo = "my-user" config.ConfigFile.TargetedOrganization = configv3.Organization{ GUID: "my-org", Name: "My Org", @@ -52,7 +59,8 @@ var _ = Describe("auth-provider", func() { APIVersion: "v1", AuthInfos: []apiv1.NamedAuthInfo{ { - Name: "one", AuthInfo: apiv1.AuthInfo{ + Name: "my-user", + AuthInfo: apiv1.AuthInfo{ AuthProvider: &apiv1.AuthProviderConfig{ Name: "oidc", Config: map[string]string{ diff --git a/integration/v7/selfcontained/login_command_test.go b/integration/v7/selfcontained/login_command_test.go index 5e41d783fec..5def6b7b457 100644 --- a/integration/v7/selfcontained/login_command_test.go +++ b/integration/v7/selfcontained/login_command_test.go @@ -6,16 +6,17 @@ import ( "os" "path/filepath" - "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" - "code.cloudfoundry.org/cli/integration/helpers" - "code.cloudfoundry.org/cli/integration/v7/selfcontained/fake" - "code.cloudfoundry.org/cli/resources" - "code.cloudfoundry.org/cli/util/configv3" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gexec" apiv1 "k8s.io/client-go/tools/clientcmd/api/v1" + + "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" + "code.cloudfoundry.org/cli/integration/helpers" + "code.cloudfoundry.org/cli/integration/v7/selfcontained/fake" + "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/configv3" ) var _ = Describe("LoginCommand", func() { @@ -45,6 +46,12 @@ var _ = Describe("LoginCommand", func() { "resources": []resources.Organization{}, }, }, + "GET /whoami": { + Code: http.StatusOK, Body: map[string]interface{}{ + "name": "two", + "kind": "User", + }, + }, }, } apiServer.SetConfiguration(apiConfig) diff --git a/integration/v7/selfcontained/logout_command_test.go b/integration/v7/selfcontained/logout_command_test.go index 55e53f35a5d..b607be4146a 100644 --- a/integration/v7/selfcontained/logout_command_test.go +++ b/integration/v7/selfcontained/logout_command_test.go @@ -1,23 +1,86 @@ package selfcontained_test import ( - "code.cloudfoundry.org/cli/integration/helpers" - "code.cloudfoundry.org/cli/util/configv3" + "net/http" + "path/filepath" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" + apiv1 "k8s.io/client-go/tools/clientcmd/api/v1" + + "code.cloudfoundry.org/cli/integration/helpers" + "code.cloudfoundry.org/cli/integration/v7/selfcontained/fake" + "code.cloudfoundry.org/cli/util/configv3" ) var _ = Describe("cf logout", func() { BeforeEach(func() { helpers.SetConfig(func(config *configv3.Config) { config.ConfigFile.CFOnK8s.Enabled = true - config.ConfigFile.CFOnK8s.AuthInfo = "something" + config.ConfigFile.CFOnK8s.AuthInfo = "my-user" }) + + apiServer.SetConfiguration(fake.CFAPIConfig{Routes: map[string]fake.Response{ + "GET /whoami": { + Code: http.StatusOK, Body: map[string]interface{}{ + "name": "my-user", + "kind": "User", + }, + }, + }}) + + kubeConfig := apiv1.Config{ + Kind: "Config", + APIVersion: "v1", + AuthInfos: []apiv1.NamedAuthInfo{ + { + Name: "my-user", + AuthInfo: apiv1.AuthInfo{ + AuthProvider: &apiv1.AuthProviderConfig{ + Name: "oidc", + Config: map[string]string{ + "id-token": string(token), + "idp-issuer-url": "-", + "client-id": "-", + }, + }, + }, + }, + }, + Clusters: []apiv1.NamedCluster{ + { + Name: "my-cluster", + Cluster: apiv1.Cluster{ + Server: "https://example.org", + }, + }, + }, + Contexts: []apiv1.NamedContext{ + { + Name: "my-context", + Context: apiv1.Context{ + Cluster: "my-cluster", + AuthInfo: "my-auth-info", + Namespace: "my-namespace", + }, + }, + }, + CurrentContext: "my-context", + } + + kubeConfigPath := filepath.Join(homeDir, ".kube", "config") + storeKubeConfig(kubeConfig, kubeConfigPath) + + env = helpers.CFEnv{ + EnvVars: map[string]string{ + "KUBECONFIG": kubeConfigPath, + }, + } }) JustBeforeEach(func() { - Eventually(helpers.CF("logout")).Should(gexec.Exit(0)) + Eventually(helpers.CustomCF(env, "logout")).Should(gexec.Exit(0)) }) It("clears the auth-info", func() { From 470d9921dde90db56c8b89214ee167d559809346 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Feb 2022 21:10:14 +0000 Subject: [PATCH 027/248] Bump github.com/docker/distribution Bumps [github.com/docker/distribution](https://github.com/docker/distribution) from 2.6.0-rc.1.0.20171109224904-e5b5e44386f7+incompatible to 2.8.0+incompatible. - [Release notes](https://github.com/docker/distribution/releases) - [Commits](https://github.com/docker/distribution/commits/v2.8.0) --- updated-dependencies: - dependency-name: github.com/docker/distribution dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index fd09459e347..e1d57e6a039 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/blang/semver v3.5.1+incompatible github.com/cloudfoundry/bosh-cli v5.5.1+incompatible github.com/cyphar/filepath-securejoin v0.2.1 - github.com/docker/distribution v2.6.0-rc.1.0.20171109224904-e5b5e44386f7+incompatible + github.com/docker/distribution v2.8.0+incompatible github.com/fatih/color v1.5.1-0.20170926111411-5df930a27be2 github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 github.com/jessevdk/go-flags v1.4.1-0.20181221193153-c0795c8afcf4 diff --git a/go.sum b/go.sum index 6ee6cbe53b0..46324f18f2e 100644 --- a/go.sum +++ b/go.sum @@ -127,8 +127,8 @@ github.com/cyphar/filepath-securejoin v0.2.1/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docker/distribution v2.6.0-rc.1.0.20171109224904-e5b5e44386f7+incompatible h1:AJ5ylGRVLdpWcAw14qENVOr/M8/s7vApzMorVhyVL78= -github.com/docker/distribution v2.6.0-rc.1.0.20171109224904-e5b5e44386f7+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.8.0+incompatible h1:l9EaZDICImO1ngI+uTifW+ZYvvz7fKISBAKpg+MbWbY= +github.com/docker/distribution v2.8.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20171120205147-9de84a78d76e h1:M+/1NNHE/mg+RUox/04+rZoahJVklPfs6xZFECVnxso= github.com/docker/docker v1.4.2-0.20171120205147-9de84a78d76e/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= From d2019369b682d1ae4b55f84d730ab0e1ce9a1326 Mon Sep 17 00:00:00 2001 From: Al Berez Date: Tue, 19 Apr 2022 11:49:06 -0700 Subject: [PATCH 028/248] [v8] Online release process with Github Actions (#2265) * Add Build-Sign-Release workflow Commit summary below Current state of CF CLI release infrastructure is offline and quite outdated. To make our release process more transparent and inclusive we decided to move build, signing and release processes online to Github Actions. * Split out release/upload part of workflow * Add capabilities to release workflow At this point working in a workflow separate from build, for separation of concerns between building&signing, and releasing. This is a squashed commit of the gha-allplatforms branch, consisting of the following changes : - Upload mac installer to S3 - include mac installer in github release - retrieve mac binaries in release job - add write permission to github release job - Add linux packages, and simplify CLAW upload steps - Switch to sync action to support simpler CLAW S3 upload step - Add linux packages to GH Release - Update artifact names in release jobs - aws s3 ls to debug s3 upload - bump aws s3 sync to non-default-region change * Updated for build, release, and units workflows * Add update-repos workflow Update-repos workflow is in charge of updating and signing on a repository level. This workflow should be triggered towards the end of the release process after all packages are available via distribution network (after CLAW update). It will update the following repositories: - Homebrew formula in homebrew-tap git repository - RPM repo hosted on S3 - Debian repo hosted on S3 Current implementations of the update-repos workflow is matching offline release process. Following updates are recommended: - Implement backup and disaster recovery procedure - Debian - fill license and vendor fields - RPM - sign on the repo level - Homebrew - add arm architecture * Release pipelines updates * Removes/Cleans comments Also, small change to sign-windows-binary.ps1 as that step was already being done in the sign job * Update github actions secrets template for use with the set-github-actions-env-vars.sh script, or the github cli's 'secret set' subcommand directly Co-authored-by: Alexander Berezovsky Co-authored-by: George Gelashvili Co-authored-by: Juan Diego Gonzalez Signed-off-by: Pete Levine --- .github/license/CF_NOTICE | 36 + .../license/LICENSE-WITH-3RD-PARTY-LICENSES | 1149 +++++++++++++++++ .github/release/gon.json | 14 + .github/secrets.template.envrc | 29 + .github/win/cf.ico | Bin 0 -> 13094 bytes .github/win/common.iss | 76 ++ .github/win/innosetup/Dockerfile | 19 + .github/win/install-innosetup.ps1 | 18 + .github/win/run-innosetup.ps1 | 20 + .github/win/sign-windows-binary.ps1 | 9 + .github/win/windows-installer-v8-x64.iss | 51 + .github/win/windows-installer-v8-x86.iss | 31 + .github/workflows/build-sign-upload.yml | 880 +++++++++++++ .github/workflows/code-quality.yml | 3 + .github/workflows/units.yml | 133 +- .github/workflows/update-repos.yml | 416 ++++++ .gitignore | 2 + Makefile | 17 +- bin/bump-version | 19 +- bin/generate-release-notes | 2 +- 20 files changed, 2846 insertions(+), 78 deletions(-) create mode 100644 .github/license/CF_NOTICE create mode 100644 .github/license/LICENSE-WITH-3RD-PARTY-LICENSES create mode 100644 .github/release/gon.json create mode 100644 .github/secrets.template.envrc create mode 100644 .github/win/cf.ico create mode 100644 .github/win/common.iss create mode 100644 .github/win/innosetup/Dockerfile create mode 100644 .github/win/install-innosetup.ps1 create mode 100644 .github/win/run-innosetup.ps1 create mode 100644 .github/win/sign-windows-binary.ps1 create mode 100644 .github/win/windows-installer-v8-x64.iss create mode 100644 .github/win/windows-installer-v8-x86.iss create mode 100644 .github/workflows/build-sign-upload.yml create mode 100644 .github/workflows/update-repos.yml diff --git a/.github/license/CF_NOTICE b/.github/license/CF_NOTICE new file mode 100644 index 00000000000..2224b281c8e --- /dev/null +++ b/.github/license/CF_NOTICE @@ -0,0 +1,36 @@ +Copyright (c) 2015-Present CloudFoundry.org Foundation, Inc. All Rights Reserved. + +This product contains software that is Copyright (c) 2013-2015 Pivotal Software, Inc. + +This product is licensed to you under the Apache License, Version 2.0 (the "License"). + +You may not use this project except in compliance with the License. + + +Attribution notices: + +This product includes software from https://github.com/cloudfoundry/cli/tree/master/vendor/code.cloudfoundry.org/gofileutils/fileutils that is: +Copyright (c) 2015-Present CloudFoundry.org Foundation, Inc. All Rights Reserved. +Copyright (c) 2014-2015 Pivotal Software, Inc. +and is licensed under the Apache License, Version 2.0. + +This product includes software from https://github.com/code.cloudfoundry.org/cli/tree/master/vendor/code.cloudfoundry.org/ykk that is: +Copyright (c) 2015-Present CloudFoundry.org Foundation, Inc. All Rights Reserved. +and is licensed under the Apache License, Version 2.0. + +This product includes software from https://github.com/code.cloudfoundry.org/cli/tree/master/vendor/code.cloudfoundry.org/cfnetworking-cli-api that is: +Copyright (c) 2016-Present CloudFoundry.org Foundation, Inc. All Rights Reserved. +and is licensed under the Apache License, Version 2.0. + +This product includes software from https://github.com/cloudfoundry/cli/tree/master/vendor/github.com/cloudfoundry/cli-plugin-repo/web that is: +Copyright (c) 2015-Present CloudFoundry.org Foundation, Inc. All Rights Reserved. +Copyright (c) 2015 Pivotal Software, Inc. +and is licensed under the Apache License, Version 2.0. + +This product includes software from https://github.com/cloudfoundry/cli/tree/master/vendor/github.com/cloudfoundry/dropsonde that is: +Copyright (c) 2014-2015 Pivotal Software, Inc. +and is licensed under the Apache License, Version 2.0. + +This product includes software from https://github.com/cloudfoundry/cli/tree/master/vendor/github.com/docker/docker/pkg/term that is: +Copyright 2012-2016 Docker, Inc. +and is licensed under the Apache License, Version 2.0. diff --git a/.github/license/LICENSE-WITH-3RD-PARTY-LICENSES b/.github/license/LICENSE-WITH-3RD-PARTY-LICENSES new file mode 100644 index 00000000000..d8ce5236b07 --- /dev/null +++ b/.github/license/LICENSE-WITH-3RD-PARTY-LICENSES @@ -0,0 +1,1149 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + + +================ + +This product includes software with separate copyright notices and +license terms, as noted below. + + +For vendor/golang.org/x/sys/unix: + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +For vendor/golang.org/x/sys/windows: + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +For vendor/golang.org/x/net/websocket: + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +For vendor/golang.org/x/crypto: + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +For vendor/github.com/blang/semver: + +The MIT License + +Copyright (c) 2014 Benedikt Lang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +For vendor/github.com/tedsuo/rata: + +The MIT License (MIT) + +Copyright (c) 2014 Ted Young + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +For vendor/github.com/golang/protobuf/ptypes/any: + +Go support for Protocol Buffers - Google's data interchange format + +Copyright 2010 The Go Authors. All rights reserved. +https://github.com/golang/protobuf + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +For vendor/github.com/golang/protobuf/proto: + +Go support for Protocol Buffers - Google's data interchange format + +Copyright 2010 The Go Authors. All rights reserved. +https://github.com/golang/protobuf + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +For vendor/github.com/jessevdk/go-flags: + +Copyright (c) 2012 Jesse van den Kieboom. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +For vendor/github.com/SermoDigital/jose: + +The MIT License (MIT) + +Copyright (c) 2015 Sermo Digital LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +For vendor/github.com/Azure/go-ansiterm: + +The MIT License (MIT) + +Copyright (c) 2015 Microsoft Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +For vendor/github.com/gogo/protobuf/protoc-gen-gogo/descriptor: + +Extensions for Protocol Buffers to create more go like structures. + +Copyright (c) 2013, Vastech SA (PTY) LTD. All rights reserved. +http://github.com/gogo/protobuf/gogoproto + +Go support for Protocol Buffers - Google's data interchange format + +Copyright 2010 The Go Authors. All rights reserved. +https://github.com/golang/protobuf + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +For vendor/github.com/gogo/protobuf/gogoproto: + +Protocol Buffers for Go with Gadgets + +Copyright (c) 2013, The GoGo Authors. All rights reserved. +http://github.com/gogo/protobuf + +Go support for Protocol Buffers - Google's data interchange format + +Copyright 2010 The Go Authors. All rights reserved. +https://github.com/golang/protobuf + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +For vendor/github.com/gogo/protobuf/proto: + +Protocol Buffers for Go with Gadgets + +Copyright (c) 2013, The GoGo Authors. All rights reserved. +http://github.com/gogo/protobuf + +Go support for Protocol Buffers - Google's data interchange format + +Copyright 2010 The Go Authors. All rights reserved. +https://github.com/golang/protobuf + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +For vendor/github.com/google/go-querystring/query: + +Copyright (c) 2013 Google. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +For vendor/github.com/mattn/go-colorable: + +The MIT License (MIT) + +Copyright (c) 2016 Yasuhiro Matsumoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +For vendor/github.com/mattn/go-isatty: + +Copyright (c) Yasuhiro MATSUMOTO + +MIT License (Expat) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +For vendor/github.com/mattn/go-runewidth: + +The MIT License (MIT) + +Copyright (c) 2016 Yasuhiro Matsumoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +For vendor/github.com/sajari/fuzzy: + +The MIT License (MIT) + +Copyright (c) 2014 Sajari Pty Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +For vendor/github.com/gorilla/websocket: + +Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +For vendor/github.com/sirupsen/logrus: + +The MIT License (MIT) + +Copyright (c) 2014 Simon Eskildsen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +For vendor/github.com/lunixbochs/vtclean: + +The MIT License (MIT) + +Copyright (c) 2015 Ryan Hileman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +For vendor/gopkg.in/cheggaaa/pb.v1: + +Copyright (c) 2012-2015, Sergey Cherepanov All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. + +* Neither the name of the author nor the names of its contributors may be used +* to endorse or promote products derived from this software without specific +* prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +For vendor/github.com/sabhiram/go-gitignore: + +The MIT License (MIT) + +Copyright (c) 2015 Shaba Abhiram + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +For portions of vendor/gopkg.in/yaml.v2: + +Copyright (c) 2006 Kirill Simonov + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +For vendor/github.com/bmatcuk/doublestar: + +The MIT License (MIT) + +Copyright (c) 2014 Bob Matcuk + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +For vendor/github.com/bmizerany/pat: + +Copyright (C) 2012 by Keith Rarick, Blake Mizerany + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +For vendor/github.com/charlievieth/fs: + +The MIT License (MIT) + +Copyright (c) 2016 Charlie Vieth + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +For vendor/github.com/cppforlife/go-patch: + +Copyright (c) 2016 Dmitriy Kalinin + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +For vendor/github.com/fatih/color: + +The MIT License (MIT) + +Copyright (c) 2013 Fatih Arslan + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +For vendor/github.com/mailru/easyjson: + +Copyright (c) 2016 Mail.Ru Group + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +For vendor/github.com/vito/go-interact: + +Copyright (c) 2015-2016 Alex Suraci + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +For vendor/github.com/pkg/errors: + +Copyright (c) 2015, Dave Cheney +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +For vendor/github.com/cyphar/filepath-securejoin: + +Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved. +Copyright (C) 2017 SUSE LLC. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +For vendor/golang.org/x/text: + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/.github/release/gon.json b/.github/release/gon.json new file mode 100644 index 00000000000..73fd4923a2a --- /dev/null +++ b/.github/release/gon.json @@ -0,0 +1,14 @@ +{ + "source" : [ + "./dist/hello-darwin_darwin_amd64/hello", + "./dist/hello-darwin_darwin_arm64/hello" + ], + "bundle_id" : "com.example.hello", + "apple_id": { + "username" : "none@example.com", + "password": "@env:AC_PASSWORD" + }, + "sign" :{ + "application_identity" : "test-sign" + } +} diff --git a/.github/secrets.template.envrc b/.github/secrets.template.envrc new file mode 100644 index 00000000000..0e955f6f089 --- /dev/null +++ b/.github/secrets.template.envrc @@ -0,0 +1,29 @@ +ACTIONS_RUNNER_DEBUG= # boolean +ACTIONS_STEP_DEBUG= # boolean +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_S3_BUCKET= +AWS_BUCKET_INTEGRATION= +AWS_BUCKET_STAGING= + +DOCKER_HUB_USERNAME= +DOCKER_HUB_ACCESS_TOKEN= + +GIT_RELEASE_TARGET_REPO= # repo to draft a release under, in / format +GIT_REPO_ACCESS_TOKEN= # only needed when pushing to a repo other than 'self' + +GIT_DEPLOY_HOMEBREW_TAP= + +SIGNING_KEY_GPG= +SIGNING_KEY_GPG_ID= +SIGNING_KEY_GPG_PASSPHRASE= + +SIGNING_CRT_MAC= +SIGNING_KEY_MAC= +SIGNING_KEY_MAC_ID= +SIGNING_KEY_MAC_PASSPHRASE= + +SIGNING_KEY_WINDOWS_PFX= +SIGNING_KEY_WINDOWS_ID= +SIGNING_KEY_WINDOWS_PASSPHRASE= + diff --git a/.github/win/cf.ico b/.github/win/cf.ico new file mode 100644 index 0000000000000000000000000000000000000000..4381126babf6c89e87ec603553f9a2404aa45960 GIT binary patch literal 13094 zcmeHN2UJwo*8c9D85jYnq5)|Z#6pY>MFj;^K&+?~1wn#?NLN&fh?GI87Q`}ev7uO> zMq{F}8;!;mHP)xtp1mX*O?jrhf1f*)K?Y3LTW|eut(Pt5&MEubr`&z^+521p4pJB! zgMQ_RlmVUq?CjL#jdEZc)phGuT{Z;#DY?0+%N<(+zgqzv2}2@4Fi{TuuuL7XJSC@o z&gj#>ANsiTL%)HpaP@G*01tP#4H<+%UY;1_?FsMU!{9w)7<@*Jz;NGD7&*olBggt; z6s56&0T{>9_(1qg2!wyocmxIqA#h?4CWKBz_>>6DNJ_%YWJ)Q?NKQ+mGzYWO=O8U3 z9dk0XFgGg`8)VV_wcQX8j!(dolYz+0QBummy!-;>73L$qr~pNa7GlwoVw5afiWOz0C@mMT zzbubZK31J9 zxwQ~SE0<6z!_f_8IJJE_r4_iiXFe|PRpRWCefaA01Gsi{AFdtSho{#BJi5FV53g*- z{YxL==&_?Xe&RUJoIQiHUwwtkS1wb!f@@dKQ@Vib*RSJ7RTXaDx`o?!?%@8N3wUt% zJf1$NqI45a9^b~B7pL*_%hR}b?;ajLdWffw@8IdPr+D`KIi7#R(l_|_+i&sW#S6TA z`4Zo~dWBc7U*pFgf5e+NZ}9WaKjW8Qe!;K5{)*pz`whSU{yYBluYc9)#$UPrnH9*& z%1R2EJk&rkFkUf>3Pe7-dM)02&(x^d5V4qG!#R%|Im)juY!g{UQh(`S|F&%dJazib z5E)Y4d%F#A9n{BTwpgUc-034m%*?1MWo1r^@EtuREVH^I)2n&#@Zl2;y{aoh<*lO~ zI!0N@Lq&#+Hu~XX+O;41p?(`tM2fjpPzQU*_a|7Jr!a$(ls*ny=S;=U z`2)!YyI}8v-uP@mKO9=(hy%sFur*@{KFS%4U3qT!WPvZ);pX^4)fy*-7G#S%;K;Jh zIJTlKzFMP)uh;Rox{5cw4zttPZ*T>@2 z<`~>KsK7rCx#QvI?znq22w7yub8_cnUS2K=78Hp#d=|B=&3*m+0bYOe3_rbkgrB~9 zjNg8Kf$zWn9zXr_pOk;~m%Y{4BL53nr6y&KkjUf_nl&}~RR0Mv@e$TC@GuNWPEC$X zu4xf}XIp^R)#a-fteJi@iE(^AhSA`8=o(v$7}459msup!dIFNIz)4z9ojoTdWlmMLCM&c+>H93^CSnp7&RV+1c3H*w}?B19(oiMZI}U zkijS>D>1~zHY8CQV+whYrhKI`xrJONw~mXpwT+G&CYR~f>z;L#86V@XH!Q)feZnx4 zfT)<%y3Xrz$;s2(x1XM@wN1^H*uFzz9sk?8Oy$fD9cC))kF1s{*>{9;rh~&w<*3p1 z)~=c%(ip9k(;Xb9DTl!%vKCd7iD(8sKpEDy?T5-h9?j}44)Me{=g?xda^eRcOjM?t z0?q5cK9b4lO;t|oLFd^FWuzX5VKsuq-xys^5}-^Q(z$!*&O_3b0a8vkMw4MI2lLFi zo}D{8cIn*3GdErC|+{+_7 zLIP8bWy&;xWJpgXsJ{;>2wG~$SB?a%l}Q8oi{zF> z)5S>5cIrE9&Wok=WOpW0YXON6e_Ubi_ zZ^d!CL7H&Nk0lM)8x;{37c@$rw0rDZ&C0AXZ12$~lh7uUjj1nPWFBuK?mwRAO(wjJ z7R#yrEt|=t@|OOZ3i|(TtOHKG-zJ2bD8IuqjP}4KpT@f8t91 ziBq+ILUCeoPwZRdjBVMT*qZ5$?eqMwW8PqVoacd$=KEp)@&Ig8#$s1~GIr!A;?u>E zI8+{wPZp(M&(b;AFU-d2mCbRYtR;?@TH$258TmB!II^@0`7~{Cyu2IEl3#Oftu8LE z=W%|W0r@u&{hO+7&2V+IKKVD!xW20^?(CG~9|!v4@Cr8^DIbp`E2rR#HGw#{GYJrNNNEv@mzH1|`8h03U9MUo`Z=p8PTgOY zfkUMQSi5c=DmQMxhD{r>Y0GA8-|-PX-n9$N|Jk>HzdASV^odTNIW77` z7cPFS_JyupL)FbHbzFLxe4(os$mjVQ&+lEs%ZF$1^3gSX_xK7PJbZvhj~`RpU5ZJc zkstH~KfV4IZ+>`)U*9|z{h&8Lyv8qYe)`J~s@Z@4CBK3;%4jB&$@R0fHEFBMG3I!l z<60JLYpkow4YiCSS3f>TPV7XSL3D0ONpW^`ZXJ(CE-M%xbYbvuxsnqbElwn3mLXX=H-PccM}7dgj5AQ==k-Tj^0(Y$oy?4X)a(%1q=p zi>;kzaePY&6)y?Sq1t++GN3V&sP|Mt z=`;r`Mz#*qN(Dh2B&S35^(oRw%3Qy2K`5}bvaw=+R&5FdA(G92*9oo9O(j)=3Gthi z2&L0|+uPb$S=;xXt`bzOh}|$U_igbEo}){WEb|1RG~eFV+CINb5Q~!qN^_RvnfK$}oL8dtj_(dBovm2M1Z2$epy(qM3>}ranT6 z8QV-oG{?mDk+@@+tTS>QnisvnC;%hooEozK%!JZWkd~T z4fs{W&zY!%)Ed?S0|vOcxh4xL6Wa3)`Gr0DGp{u~`rtyXlk zG=8|6*T-krtTHl)w9YzObXuISlwM3(`siUkM56-INou^5#M72&NHMj_zG7}lU|`DJ z6~vQk$n+_cV^RmZ7ad-VXjQ}0E0>g*dPi>#Hxdbdclj`sgE2^ck1eImSY3_C{Fc< z|Ag@vKQWl@)I-HPbr!EGrmFAMqv%dOb{gHOPoIYAGiQk3EoY@BBPDG%(z7y9t{92( zD2i97P`nyF8mnV`Q9<|WYiEw4cy+iKudYoTjdjz5v2oUi*q9tH#;oi<{j;Jzbf^A- zc&A<$vks-0)t6${K@_vP#QhFl~l*59Ik9J!Pnac;Ldj7?oM6YJJ1tHR72<5RcU6Df`!WXKTuj2fQ;BphpN;wXbSF>o zsxo(;crU-WWQlk$zl>tlvX$j1r+fKTYgW^@TO|$(g;+~>^y^u?O5asCZ`~rstL&R9 zyQ|-KV80l*9z1+Vj9X7^&ZqCItMJ8!6*%|lLP|?Nj$E)iYGU(;hTH6@#^6bynJ#CZ(iTVeY)3w^!Sk&$Fi9A z#mg6X_3Sa;{P-L{|44WI;+_6a_~-X8DYpIouXwg*pZyWht@f@ZGo}bjj z2nytNSUQWPB8i81jY!_0pb30Mi)uW5P%xRONXX02&r67!XhxqKY6M3&0k0H{MK+#q z9$vVrjm9_)vf{+g;C-vac0zBF{@pT02`ZjvuF(} zEJWqdZ535S!n9MVH5-6*3TrJ%i|p9erj2d8$g~nxj$_+FYT5K=ERr(;I$`4aS46gL zYikq9z?FhRm*AZFO0m@FBVNj}6_gk$SU*$k?Aq8&rOd);Q}O+aQ)?7V4W)|ay1KMY zI9?vIvNFlW&ekTWa^)n7E!fME8bxV+b(#`O3kwSpLYq@}36*KKZ5(XVD&r)a%rqo6 zZ$@6NanM9)%a>Y6B~g`gY}>SPNUNN}$>ZMH?^{xYg7}4%b8Q{k*v_q7G`;CXe+yby z%xXiFRagGAxeN!Qe+%En!C}dt?X`}7i9>q_hm5-NpU73P1@6_Vx@P1=)LAH$AmApp}zptME}&pG9yHA5W2#ZulP? zLa7DYL9#r;r`y|iuurEXR~}1tEQV4v4K@+r6P4Vl8LN!nRE9Z-Fx)v?!1Bu6;@1ugg0n% z2}0GQG%siPE{8!qSW;70clR8sZY55Dsisz%NM{7kv5o83 zmB7_l4-a>D_d#xcR2|9=5nfadZ33*=0m~^WD=U1vdU()H8zuU4b)`SoF*E@M!*f>J zu&mCKjh}7&b)yFmnve`gG|<(x|1iQwF%94>8^g2yC9MDT;|5eCUD;({|NfpXE@NpM zio3A!{wIm}NhIFi)z#CLecbnCmwAH+5BBm3rfM}qNMrpgL_E`vBY!rIV}rQ zAfAtC44)?|sGKSI1TX4RByTTo@1fq_6R5IC)Gz6b#_($W5EXpQSTDj6(RCrCz%>LC zw}+@-jYwb~l7urZqh{6kpN3(NJ0*0G*U@x zUs*X>w1MLGXhcM{`zvR*yRve1Zct!AKwwZV8+&DCp6H#b4YOFGcj2T?Qzr%tT$kl9m^&PE>D79J@>nh%Hc-2TrP&>QzWYGUoNvvsq=Wpp`{knjQ#L!Ii z!^y1vaVk=n>e5zat4>c{Ger}pj&`X+{$z6_JzZV7p}8Wj_Ek3E{SRL+{3ZUsd ExpandConstant('{userappdata}\Cloud Foundry')) AND + (WizardDirValue <> ExpandConstant('{pf}\Cloud Foundry')) then + begin + Log('User has selected a custom install path. Will not override.') + end + else if OptionPage.Values[1] then + begin + // override the default installation to program files ({pf}) + WizardForm.DirEdit.Text := ExpandConstant('{userappdata}\Cloud Foundry') + end + else + begin + WizardForm.DirEdit.Text := ExpandConstant('{pf}\Cloud Foundry'); + end; + end; + Result := True; +end; diff --git a/.github/win/innosetup/Dockerfile b/.github/win/innosetup/Dockerfile new file mode 100644 index 00000000000..0a0d5a18ed3 --- /dev/null +++ b/.github/win/innosetup/Dockerfile @@ -0,0 +1,19 @@ +# This image is not being used by the github actions workflow +# because gh-actions doesn't support windows based images +# Keeping this file as we expect to use it in the future +FROM mcr.microsoft.com/windows/servercore:ltsc2019 +SHELL ["powershell.exe"] + +ARG CHOCO_THUMBPRINT=83AC7D88C66CB8680BCE802E0F0F5C179722764B +RUN mkdir \setup + +RUN (New-Object System.Net.WebClient).DownloadFile('https://chocolatey.org/install.ps1', '\setup\installChocolatey.ps1') +RUN (Get-AuthenticodeSignature \setup\installChocolatey.ps1).SignerCertificate.Thumbprint > \setup\thumbprint +RUN if ((type \setup\thumbprint) -ne $env:CHOCO_THUMBPRINT) { \ + throw 'chocolatey installer thumbprint does not match expected. see https://docs.chocolatey.org/en-us/information/security' \ + } +RUN \setup\installChocolatey.ps1 +RUN Remove-Item -Recurse \setup + + +RUN choco install --no-progress -r -y innosetup diff --git a/.github/win/install-innosetup.ps1 b/.github/win/install-innosetup.ps1 new file mode 100644 index 00000000000..14c64bf0908 --- /dev/null +++ b/.github/win/install-innosetup.ps1 @@ -0,0 +1,18 @@ +$ErrorActionPreference = "Stop" +# in the future, this variable should cause PS to exit on non-zero exit codes from commands/exes (as opposed to PS cmdlets) +$PSNativeCommandUseErrorActionPreference = $true +# see https://github.com/PowerShell/PowerShell/issues/3415 and https://github.com/PowerShell/PowerShell-RFC/pull/277 + +# retrieved from https://docs.chocolatey.org/en-us/information/security +$chocoThumbprint = '83AC7D88C66CB8680BCE802E0F0F5C179722764B' + +$scriptPath = (Get-Location).Path + '\installChocolatey.ps1' +(New-Object System.Net.WebClient).DownloadFile('https://chocolatey.org/install.ps1', $scriptPath) +(Get-AuthenticodeSignature .\installChocolatey.ps1).SignerCertificate.Thumbprint -eq $chocoThumbprint + +Set-ExecutionPolicy Bypass -Scope Process +.\installChocolatey.ps1 + +choco install --no-progress -r -y innosetup --force + +Get-Command iscc -ErrorAction Continue diff --git a/.github/win/run-innosetup.ps1 b/.github/win/run-innosetup.ps1 new file mode 100644 index 00000000000..b1f1143550a --- /dev/null +++ b/.github/win/run-innosetup.ps1 @@ -0,0 +1,20 @@ +param ($InnoSetupConfig, $CfBinary, $InstallerOutput) + +$ErrorActionPreference = "Stop" +# in the future, this variable should cause PS to exit on non-zero exit codes from commands/exes (as opposed to PS cmdlets) +$PSNativeCommandUseErrorActionPreference = $true +# see https://github.com/PowerShell/PowerShell/issues/3415 and https://github.com/PowerShell/PowerShell-RFC/pull/277 + +$innoSetupWorkDir = "$PSScriptRoot" +$licenseDir = "${PSScriptRoot}\..\license" + +Move-Item -Force "$CfBinary" $innoSetupWorkDir\cf8.exe + +# convert line-endings +Get-Content ${licenseDir}\LICENSE-WITH-3RD-PARTY-LICENSES | Set-Content "${innoSetupWorkDir}\LICENSE" +Get-Content ${licenseDir}\CF_NOTICE | Set-Content "${innoSetupWorkDir}\NOTICE" + +iscc "$InnoSetupConfig" +Move-Item "${innoSetupWorkDir}\Output\mysetup.exe" "$InstallerOutput" + +Get-ChildItem "${innoSetupWorkDir}\Output" diff --git a/.github/win/sign-windows-binary.ps1 b/.github/win/sign-windows-binary.ps1 new file mode 100644 index 00000000000..684b2ab1562 --- /dev/null +++ b/.github/win/sign-windows-binary.ps1 @@ -0,0 +1,9 @@ +# expected environment variables +# SIGNING_KEY_WINDOWS_PASSPHRASE + +param ($BinaryFilePath) + +# add PATH to signtool.exe +$env:PATH="$env:PATH;C:\Program Files (x86)\Windows Kits\10\bin\x64" + +signtool sign /v /p "$env:SIGNING_KEY_WINDOWS_PASSPHRASE" /fd SHA256 /f "$env:RUNNER_TEMP\cert.pfx" "$BinaryFilePath" diff --git a/.github/win/windows-installer-v8-x64.iss b/.github/win/windows-installer-v8-x64.iss new file mode 100644 index 00000000000..c11acb04151 --- /dev/null +++ b/.github/win/windows-installer-v8-x64.iss @@ -0,0 +1,51 @@ +[Setup] +ChangesEnvironment=yes +AlwaysShowDirOnReadyPage=yes +AppName=Cloud Foundry CLI +AppVersion=VERSION +AppVerName=Cloud Foundry CLI version VERSION +AppPublisher=Cloud Foundry Foundation +ArchitecturesInstallIn64BitMode=x64 ia64 +ArchitecturesAllowed=x64 ia64 +PrivilegesRequired=none +DefaultDirName={pf}\Cloud Foundry +SetupIconFile=cf.ico +UninstallDisplayIcon={app}\cf.ico + +[Registry] +Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}"; Check: IsAdminLoggedOn and Uninstall32Bit() and NeedsAddPath(ExpandConstant('{app}')) +Root: HKCU; Subkey: "Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}"; Check: not IsAdminLoggedOn and Uninstall32Bit() and NeedsAddPath(ExpandConstant('{app}')) + +[Files] +Source: LICENSE; DestDir: "{app}" +Source: NOTICE; DestDir: "{app}" +Source: cf8.exe; DestDir: "{app}" +Source: cf.ico; DestDir: "{app}" + +[Run] +Filename: "{cmd}"; Parameters: "/C mklink ""{app}\cf.exe"" ""{app}\cf8.exe""" + +[UninstallDelete] +Type: files; Name: "{app}\cf.exe" +Type: dirifempty; Name: "{app}" + +[Code] +function Uninstall32Bit(): Boolean; +var + resultCode: Integer; + uninstallString: String; + uninstallStringPath: String; +begin + uninstallString := ''; + uninstallStringPath := 'SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Cloud Foundry CLI_is1'; + RegQueryStringValue(HKLM, uninstallStringPath, 'UninstallString', uninstallString); + + if uninstallString <> '' then + begin + uninstallString := RemoveQuotes(uninstallString); + Exec(uninstallString, '/VERYSILENT /SUPPRESSMSGBOXES /NORESTART','', SW_HIDE, ewWaitUntilTerminated, resultCode) + end; + Result := true; +end; + +#include "common.iss" diff --git a/.github/win/windows-installer-v8-x86.iss b/.github/win/windows-installer-v8-x86.iss new file mode 100644 index 00000000000..aa3343d012b --- /dev/null +++ b/.github/win/windows-installer-v8-x86.iss @@ -0,0 +1,31 @@ +[Setup] +ChangesEnvironment=yes +AlwaysShowDirOnReadyPage=yes +AppName=Cloud Foundry CLI +AppVersion=VERSION +AppVerName=Cloud Foundry CLI version VERSION +AppPublisher=Cloud Foundry Foundation +PrivilegesRequired=none +DefaultDirName={pf}\Cloud Foundry +SetupIconFile=cf.ico +UninstallDisplayIcon={app}\cf.ico + +[Registry] +Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}"; Check: IsAdminLoggedOn and NeedsAddPath(ExpandConstant('{app}')) +Root: HKCU; Subkey: "Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}"; Check: not IsAdminLoggedOn and NeedsAddPath(ExpandConstant('{app}')) + +[Files] +Source: LICENSE; DestDir: "{app}" +Source: NOTICE; DestDir: "{app}" +Source: cf8.exe; DestDir: "{app}" +Source: cf.ico; DestDir: "{app}" + +[Run] +Filename: "{cmd}"; Parameters: "/C mklink ""{app}\cf.exe"" ""{app}\cf8.exe""" + +[UninstallDelete] +Type: files; Name: "{app}\cf.exe" +Type: dirifempty; Name: "{app}" + +[Code] +#include "common.iss" diff --git a/.github/workflows/build-sign-upload.yml b/.github/workflows/build-sign-upload.yml new file mode 100644 index 00000000000..37bbdeaccdf --- /dev/null +++ b/.github/workflows/build-sign-upload.yml @@ -0,0 +1,880 @@ + +name: Build-Sign-Upload + +on: + push: + tags: + - 'v8.*' + +permissions: + contents: read + +defaults: + # top-level defaults subkeys apply to jobs + # run subkeys apply to all steps within all jobs + run: + shell: bash + +jobs: + setup: + name: Setup + runs-on: ubuntu-latest + if: ${{ github.action_repository != 'cloudfoundry/cli' }} + outputs: + secrets-environment: ${{ steps.set-secrets-environment.outputs.secrets-environment }} + build-version: ${{ steps.set-build-version.outputs.build-version }} + go-version: ${{ steps.set-go-version.outputs.go-version }} + steps: + # note the key must be 'id' and not 'name' here, to be accessed via the steps. syntax above + + - name: Set environment + id: set-secrets-environment + run: echo "::set-output name=secrets-environment::PROD" + + - name: Checkout cli + uses: actions/checkout@v2 + + - name: Check if BUILD_VERSION matches tag ${{ github.ref }} + run: | + echo "Git Ref: ${{ github.ref }}" + echo "BUILD_VERSION: $(cat BUILD_VERSION)" + + exit 0 + + - name: Set build version + id: set-build-version + run: | + version=$(cat BUILD_VERSION) + echo "::set-output name=build-version::$version" + + - name: Set go version + id: set-go-version + run: echo "::set-output name=go-version::1.17" + + # This is for debugging. It's equivalent to fly intecept + # - name: Setup upterm session + # env: + # AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + # if: always() + # uses: lhotari/action-upterm@v1 + # timeout-minutes: 60 + + test-rpm-package: + name: Test RPM Artifacts + needs: build-linux + runs-on: ubuntu-latest + container: + image: fedora + steps: + + - name: Download Signed Linux Packages + uses: actions/download-artifact@v2 + with: + name: cf-cli-linux-rpm-packages + + - name: Display structure of downloaded files + run: ls -R + + - name: Test RPMs + run: | + rpm -q --qf 'FN:\t%{FILENAMES}\nNAME:\t%{NAME}\nPGP:\t%{SIGPGP:pgpsig}\nGPG:\t%{SIGGPG:pgpsig}\n' -p *.rpm + + test-deb-package: + name: Test Debian Artifacts + needs: build-linux + runs-on: ubuntu-latest + container: + image: ubuntu + steps: + + - name: Download Signed Linux Packages + uses: actions/download-artifact@v2 + with: + name: cf-cli-linux-deb-packages + + - name: Display structure of downloaded files + run: | + ls -R + ls *.deb | xargs -n1 dpkg --info + + test-macos: + name: Test macOS Artifacts + needs: build-macos + runs-on: macos-latest + steps: + + - name: Download Signed macOS Packages + uses: actions/download-artifact@v2 + with: + name: cf-cli-macos-packages + + - name: Inspect macOS packages + run: | + ls -R + pkgutil --check-signature * + + test-windows: + name: Test Windows Artifacts + needs: build-windows + runs-on: windows-latest + defaults: + run: + shell: pwsh + steps: + + - name: Download Signed Windows Binaries + uses: actions/download-artifact@v2 + with: + name: cf-cli-windows-binaries + + - name: Inspect Windows packages + run: | + Get-AuthenticodeSignature -Verbose -ErrorAction Stop .\cf-cli_win32.exe + Get-AuthenticodeSignature -Verbose -ErrorAction Stop .\cf-cli_winx64.exe + + - name: Download Signed Windows Binaries + uses: actions/download-artifact@v2 + with: + name: cf-cli-windows-packages + + - name: Inspect Windows files + run: | + Get-ChildItem -Force + + - name: View installer signature + run: | + Expand-Archive -DestinationPath winx64 -Path cf8-cli-installer_*_winx64.zip + Expand-Archive -DestinationPath win32 -Path cf8-cli-installer_*_win32.zip + + Get-AuthenticodeSignature -Verbose -ErrorAction Stop ".\winx64\cf8_installer.exe" + Get-AuthenticodeSignature -Verbose -ErrorAction Stop ".\win32\cf8_installer.exe" + + build-linux: + name: Build Linux + needs: + - setup + runs-on: ubuntu-latest + environment: ${{ needs.setup.outputs.secrets-environment }} + + env: + BUILD_VERSION: ${{ needs.setup.outputs.build-version }} + + steps: + + - name: Get Build Version + id: get_build_version + run: echo "BUILD_VERSION $BUILD_VERSION" + + - name: Checkout cli + uses: actions/checkout@v2 + + - name: Checkout cli-ci + uses: actions/checkout@v2 + with: + repository: cloudfoundry/cli-ci.git + path: cli-ci + ref: master + + - name: Install Linux Packages + run: sudo apt update && sudo apt install -y --no-install-recommends fakeroot + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: ${{ needs.setup.outputs.go-version }} + + - name: Print go environment + id: go-cache-paths + run: | + echo "::set-output name=go-build::$(go env GOCACHE)" + echo "::set-output name=go-mod::$(go env GOMODCACHE)" + go env + + - name: Go Assets Cache + uses: actions/cache@v2 + with: + path: | + ${{ steps.go-cache-paths.outputs.go-mod }} + ${{ steps.go-cache-paths.outputs.go-build }} + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Build Linux + run: | + make out/cf-cli_linux_i686 + make out/cf-cli_linux_x86-64 + + - name: Store Linux Binaries + uses: actions/upload-artifact@v2 + with: + if-no-files-found: error + name: cf-cli-linux-binaries + path: out/cf-cli_linux* + + - name: Build RedHat Packages + env: + SIGNING_KEY_GPG_ID: ${{ secrets.SIGNING_KEY_GPG_ID }} + run: | + set -ex + set -o pipefail + + root=$PWD + + cat<< EOF >~/.rpmmacros + $SIGNING_KEY_GPG_ID + EOF + + RPM_VERSION=${BUILD_VERSION//-/_} + + mkdir -pv $root/packaged + + echo "Build 32-bit RedHat package" + ( + pushd cli-ci/ci/installers/rpm + cp $root/out/cf-cli_linux_i686 cf8 + cp ../../license/NOTICE . + cp ../../license/LICENSE-WITH-3RD-PARTY-LICENSES LICENSE + cp ../completion/cf8 cf8.bash + echo "Version: ${RPM_VERSION}" > cf-cli.spec + cat cf8-cli.spec.template >> cf-cli.spec + rpmbuild --target i386 --define "_topdir $(pwd)/build" -bb cf-cli.spec + mv build/RPMS/i386/cf8-cli*.rpm $root/packaged/cf8-cli-installer_${BUILD_VERSION}_i686.rpm + popd + ) + + + echo "Build 64-bit RedHat package" + ( + pushd cli-ci/ci/installers/rpm + cp $root/out/cf-cli_linux_x86-64 cf8 + cp ../../license/NOTICE . + cp ../../license/LICENSE-WITH-3RD-PARTY-LICENSES LICENSE + cp ../completion/cf8 cf8.bash + echo "Version: ${RPM_VERSION}" > cf-cli.spec + cat cf8-cli.spec.template >> cf-cli.spec + rpmbuild --target x86_64 --define "_topdir $(pwd)/build" -bb cf-cli.spec + mv build/RPMS/x86_64/cf8-cli*.rpm $root/packaged/cf8-cli-installer_${BUILD_VERSION}_x86-64.rpm + popd + ) + + - name: Load GPG key + env: + SIGNING_KEY_GPG: ${{ secrets.SIGNING_KEY_GPG }} + run: | + echo -n "$SIGNING_KEY_GPG" | base64 --decode | gpg --no-tty --batch --pinentry-mode loopback --import + + - name: View GPG keys + run: | + gpg --list-keys + + - name: Sign RedHat Packages + env: + SIGNING_KEY_GPG_ID: ${{ secrets.SIGNING_KEY_GPG_ID }} + SIGNING_KEY_GPG_PASSPHRASE: ${{ secrets.SIGNING_KEY_GPG_PASSPHRASE }} + run: | + set -ex + set -o pipefail + + SUFFIX=8 + + mkdir signed-redhat-installer + + cat<< EOF >~/.rpmmacros + %_gpg_name $SIGNING_KEY_GPG_ID + EOF + + cp packaged/cf*.rpm signed-redhat-installer/ + + # TODO: consider to add --key-id + rpmsign --addsign signed-redhat-installer/*.rpm + + - name: Print RPM Signature + run: rpm -q --qf 'FN:\t%{FILENAMES}\nNAME:\t%{NAME}\nPGP:\t%{SIGPGP:pgpsig}\nGPG:\t%{SIGGPG:pgpsig}\n' -p *.rpm + working-directory: signed-redhat-installer + + - name: Store Signed Linux RPM Packages + uses: actions/upload-artifact@v2 + with: + if-no-files-found: error + name: cf-cli-linux-rpm-packages + path: signed-redhat-installer/*.rpm + + + - name: Build Debian Packages + run: | + set -ex + set -o pipefail + + root=$PWD + + mkdir -pv $root/packaged-deb + + echo "Build 32-bit Debian package" + ( + SIZE="$(BLOCKSIZE=1000 du $root/out/cf-cli_linux_i686 | cut -f 1)" + + pushd cli-ci/ci/installers/deb + mkdir -p cf/usr/bin cf/usr/share/doc/cf8-cli/ cf/DEBIAN cf/usr/share/bash-completion/completions + + cp copyright_preamble cf/DEBIAN/copyright + sed 's/^$/ ./' $root/LICENSE >> cf/DEBIAN/copyright + cat copyright_comment_header >> cf/DEBIAN/copyright + sed 's/^$/ ./' ../../license/3RD-PARTY-LICENSES >> cf/DEBIAN/copyright + + cp cf/DEBIAN/copyright cf/usr/share/doc/cf8-cli/copyright + + cp ../../license/NOTICE cf/usr/share/doc/cf8-cli + cp ../../license/LICENSE-WITH-3RD-PARTY-LICENSES cf/usr/share/doc/cf8-cli/LICENSE + + cp control_v8.template cf/DEBIAN/control + echo "Installed-Size: ${SIZE}" >> cf/DEBIAN/control + echo "Version: ${BUILD_VERSION}" >> cf/DEBIAN/control + echo "Architecture: i386" >> cf/DEBIAN/control + + cp ../completion/cf8 cf/usr/share/bash-completion/completions/cf8 + + cp $root/out/cf-cli_linux_i686 cf/usr/bin/cf8 + ln -frs cf/usr/bin/cf8 cf/usr/bin/cf + + fakeroot dpkg --build cf cf8-cli-installer_${BUILD_VERSION}_i686.deb + mv cf8-cli-installer_${BUILD_VERSION}_i686.deb $root/packaged-deb + rm -rf cf + popd + ) + + echo "Build 64-bit Debian package" + ( + SIZE="$(BLOCKSIZE=1000 du $root/out/cf-cli_linux_x86-64 | cut -f 1)" + + pushd cli-ci/ci/installers/deb + mkdir -p cf/usr/bin cf/usr/share/doc/cf8-cli/ cf/DEBIAN cf/usr/share/bash-completion/completions + + cp copyright_preamble cf/DEBIAN/copyright + sed 's/^$/ ./' $root/LICENSE >> cf/DEBIAN/copyright + cat copyright_comment_header >> cf/DEBIAN/copyright + sed 's/^$/ ./' ../../license/3RD-PARTY-LICENSES >> cf/DEBIAN/copyright + + cp cf/DEBIAN/copyright cf/usr/share/doc/cf8-cli/copyright + + cp ../../license/NOTICE cf/usr/share/doc/cf8-cli + cp ../../license/LICENSE-WITH-3RD-PARTY-LICENSES cf/usr/share/doc/cf8-cli/LICENSE + + cp control_v8.template cf/DEBIAN/control + echo "Installed-Size: ${SIZE}" >> cf/DEBIAN/control + echo "Version: ${BUILD_VERSION}" >> cf/DEBIAN/control + echo "Architecture: amd64" >> cf/DEBIAN/control + + cp ../completion/cf8 cf/usr/share/bash-completion/completions/cf8 + + cp $root/out/cf-cli_linux_x86-64 cf/usr/bin/cf8 + ln -frs cf/usr/bin/cf8 cf/usr/bin/cf + + fakeroot dpkg --build cf cf8-cli-installer_${BUILD_VERSION}_x86-64.deb + mv cf8-cli-installer_${BUILD_VERSION}_x86-64.deb $root/packaged-deb + popd + ) + + - name: Print DEB Packages Info + run: | + ls -R + for f in *.deb; do + echo $f + dpkg --info $f + done + working-directory: packaged-deb + + - name: Store Debian Packages + uses: actions/upload-artifact@v2 + with: + if-no-files-found: error + name: cf-cli-linux-deb-packages + path: packaged-deb/*.deb + + build-macos: + name: Build macOS + needs: + - setup + runs-on: macos-latest + environment: ${{ needs.setup.outputs.secrets-environment }} + steps: + + - name: Setup + run: | + echo "BUILD_VERSION=${{ needs.setup.outputs.build-version }}" >> $GITHUB_ENV + + - name: Get Build Version + id: get_build_version + run: echo "BUILD_VERSION $BUILD_VERSION" + + - name: Checkout cli + uses: actions/checkout@v2 + + - name: Checkout cli-ci + uses: actions/checkout@v2 + with: + repository: cloudfoundry/cli-ci.git + path: cli-ci + ref: master + + - name: Checkout bomutils + uses: actions/checkout@v2 + with: + repository: hogliux/bomutils.git + ref: 0.2 + path: bomutils + + - name: Build bomutils + working-directory: bomutils + run: make + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: ${{ needs.setup.outputs.go-version }} + + - name: Update Homebrew + run: | + brew tap pivotalsoftware/gon + brew update --preinstall + cat "$(brew --repository)/Library/Taps/pivotalsoftware/homebrew-gon/gon.rb" > .github/brew-formulae + + - name: Configure Homebrew cache + uses: actions/cache@v2 + with: + path: | + ~/Library/Caches/Homebrew/gon--* + ~/Library/Caches/Homebrew/downloads/*--gon-* + key: brew-${{ hashFiles('.github/brew-formulae') }} + restore-keys: brew- + + - name: Install Homebrew dependencies + run: | + env HOMEBREW_NO_AUTO_UPDATE=1 brew install pivotalsoftware/gon/gon coreutils + + - name: Print go environment + id: go-cache-paths + run: | + echo "::set-output name=go-build::$(go env GOCACHE)" + echo "::set-output name=go-mod::$(go env GOMODCACHE)" + go env + + - name: Go Assets Cache + uses: actions/cache@v2 + with: + path: | + ${{ steps.go-cache-paths.outputs.go-mod }} + ${{ steps.go-cache-paths.outputs.go-build }} + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Build macOS Binaries + run: | + make out/cf-cli_osx + make out/cf-cli_osx_arm + + - name: Store macOS Binaries + uses: actions/upload-artifact@v2 + with: + if-no-files-found: error + name: cf-cli-macos-binaries + path: out/cf-cli* + + - name: Build macOS Installer + run: | + set -ex + set -o pipefail + + root=$PWD + + mkdir -pv $root/packaged + + echo "Building OS X installer" + ( + SIZE="$(BLOCKSIZE=1000 du $root/out/cf-cli_osx | cut -f 1)" + + pushd cli-ci/ci/installers/osx_v8 + sed -i -e "s/VERSION/${BUILD_VERSION}/g" Distribution + sed -i -e "s/SIZE/${SIZE}/g" Distribution + mkdir -p cf-cli/usr/local/bin cf-cli/usr/local/share/doc/cf8-cli + + cp $root/out/cf-cli_osx cf-cli/usr/local/bin/cf8 + gln -frs cf-cli/usr/local/bin/cf8 cf-cli/usr/local/bin/cf + cp ../../license/NOTICE cf-cli/usr/local/share/doc/cf8-cli + cp ../../license/LICENSE-WITH-3RD-PARTY-LICENSES cf-cli/usr/local/share/doc/cf8-cli/LICENSE + chmod -R go-w cf-cli + pushd cf-cli + find usr | cpio -o --format=odc | gzip -c > ../Payload + popd + + $root/bomutils/build/bin/ls4mkbom cf-cli | sed 's/1000\/1000/0\/80/' > bom_list + mkbom -i bom_list Bom + mv Bom Payload com.cloudfoundry.cf8-cli.pkg + xar -c --compression none -f cf8-cli-installer_osx.pkg com.cloudfoundry.cf8-cli.pkg Distribution + mv cf8-cli-installer_osx.pkg $root/packaged/cf8-cli-installer_osx.pkg + popd + ) + + - name: Load macos key + env: + SIGNING_TEST_CA_MAC: ${{ secrets.SIGNING_TEST_CA_MAC }} + SIGNING_KEYCHAIN_PASSPHRASE: ${{ secrets.SIGNING_KEYCHAIN_PASSPHRASE }} + + SIGNING_KEY_MAC: ${{ secrets.SIGNING_KEY_MAC }} + SIGNING_KEY_MAC_ID: ${{ secrets.SIGNING_KEY_MAC_ID }} + SIGNING_KEY_MAC_PASSPHRASE: ${{ secrets.SIGNING_KEY_MAC_PASSPHRASE }} + SIGNING_KEY_MAC_PFX: ${{ secrets.SIGNING_KEY_MAC_PFX }} + + run: | + echo -n "$SIGNING_KEY_MAC_PFX" | base64 --decode > mac-signing-key.p12 + security list-keychains -d user -s login + + ORIGINAL_KEYCHAIN="$(security default-keychain | sed -e 's/[ "]*\([^"]*\)[ "]*/\1/')" + KEYCHAIN_PATH="$HOME/Library/Keychains/build.keychain-db" + + # Create build keychain + security create-keychain -p "$SIGNING_KEYCHAIN_PASSPHRASE" "$KEYCHAIN_PATH" + # trap "security delete-keychain $KEYCHAIN_PATH" 0 + + # Append build keychain to the user domain + security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | sed s/\"//g) + + # Remove relock timeout + security set-keychain-settings "$KEYCHAIN_PATH" + + # Unlock build keychain + security unlock-keychain -p "$SIGNING_KEYCHAIN_PASSPHRASE" "$KEYCHAIN_PATH" + + # Add certificate to keychain + security import mac-signing-key.p12 -k "$KEYCHAIN_PATH" -P "$SIGNING_KEY_MAC_PASSPHRASE" -A -T $(which codesign) -T $(which productsign) + + # Enable codesigning from a non user interactive shell + security set-key-partition-list -S apple-tool:,apple:, -s -k "$SIGNING_KEYCHAIN_PASSPHRASE" -D "${IDENTITY_CERTIFICATE}" -t private "$KEYCHAIN_PATH" || echo set-key-partition-list private failed + rm mac-signing-key.p12 + + #TODO: clean keychain in a separate step + # Delete build keychain + # security delete-keychain "$KEYCHAIN_PATH" + + - name: Sign macOS + env: + SUFFIX: 8 + SIGNING_KEY_MAC_ID: ${{ secrets.SIGNING_KEY_MAC_ID }} + SIGNING_KEY_MAC_PASSPHRASE: ${{ secrets.SIGNING_KEY_MAC_PASSPHRASE }} + run: | + + root=$PWD + + mkdir -pv signed-osx-installer + + productsign --timestamp \ + --sign "$SIGNING_KEY_MAC_ID" \ + "$root/packaged/cf${SUFFIX}-cli-installer_osx.pkg" \ + "signed-osx-installer/cf${SUFFIX}-cli-installer_${BUILD_VERSION}_osx.pkg" + + - name: Store macOS Signed Packages + uses: actions/upload-artifact@v2 + with: + if-no-files-found: error + name: cf-cli-macos-packages + path: signed-osx-installer/*.pkg + + + build-windows: + name: Build Windows + needs: + - setup + runs-on: windows-2019 + environment: ${{ needs.setup.outputs.secrets-environment }} + defaults: + run: + shell: pwsh + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: ${{ needs.setup.outputs.go-version }} + + - name: Get build-time dependencies + run: | + choco install --no-progress --limit-output -y make + go install github.com/akavel/rsrc@v0.10.2 + + - name: Build CF CLI for Windows + run: | + Get-Command make + Get-Item Makefile + make out/cf-cli_win32.exe + make out/cf-cli_winx64.exe + + - name: write windows cert + run: | + $pass = convertto-securestring -string "$env:SIGNING_KEY_WINDOWS_PASSPHRASE" -asplaintext + [convert]::frombase64string($env:SIGNING_KEY_WINDOWS_PFX) | set-content -path $env:runner_temp\cert.pfx -asbytestream + + env: + SIGNING_KEY_WINDOWS_PFX: ${{ secrets.SIGNING_KEY_WINDOWS_PFX }} + SIGNING_KEY_WINDOWS_PASSPHRASE: ${{ secrets.SIGNING_KEY_WINDOWS_PASSPHRASE }} + + - name: Sign windows binaries + run: | + .\.github\win\sign-windows-binary.ps1 -BinaryFilePath out\cf-cli_win32.exe + .\.github\win\sign-windows-binary.ps1 -BinaryFilePath out\cf-cli_winx64.exe + env: + SIGNING_KEY_WINDOWS_PASSPHRASE: ${{ secrets.SIGNING_KEY_WINDOWS_PASSPHRASE }} + + - name: View binary signatures + run: | + Get-AuthenticodeSignature -Verbose -ErrorAction Stop .\out\cf-cli_win32.exe + Get-AuthenticodeSignature -Verbose -ErrorAction Stop .\out\cf-cli_winx64.exe + + - name: Make symlinks + run: | + New-Item -ItemType SymbolicLink -Target .\out\cf-cli_win32.exe -Path .\out\cf-cli_win32-link.exe + New-Item -ItemType SymbolicLink -Target .\out\cf-cli_winx64.exe -Path .\out\cf-cli_winx64-link.exe + + # This is for debugging windows + # - name: enable ssh + # if: always() + # run: | + # Get-WindowsCapability -Online + # $componentName = $(Get-WindowsCapability -Online |Where-Object Name -like 'OpenSSH.Server*').Name + # Add-WindowsCapability -Online -Name $componentName + # Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" + + # - name: ssh session + # if: always() + # run: | + # Start-Service sshd + # echo "IP address below:" + # Get-NetIPAddress | Select-Object -Property IPAddress + # sleep 3600 + # Stop-Service sshd + + - name: Save signed binaries as a GitHub Action Artifact + uses: actions/upload-artifact@v2 + with: + name: cf-cli-windows-binaries + if-no-files-found: error + path: out/cf-cli_win*.exe + + - name: Install innosetup + run: .\.github\win\install-innosetup.ps1 + + - name: Run innosetup + run: | + mkdir "$env:RUNNER_TEMP\winx64" + .\.github\win\run-innosetup.ps1 -InnoSetupConfig ".github\win\windows-installer-v8-x64.iss" -CfBinary "out\cf-cli_winx64.exe" -InstallerOutput "$env:RUNNER_TEMP\winx64\cf8_installer.exe" + mkdir "$env:RUNNER_TEMP\win32" + .\.github\win\run-innosetup.ps1 -InnoSetupConfig ".github\win\windows-installer-v8-x86.iss" -CfBinary "out\cf-cli_win32.exe" -InstallerOutput "$env:RUNNER_TEMP\win32\cf8_installer.exe" + + - name: Sign windows installer + run: | + .\.github\win\sign-windows-binary.ps1 -BinaryFilePath "$env:RUNNER_TEMP\winx64\cf8_installer.exe" + .\.github\win\sign-windows-binary.ps1 -BinaryFilePath "$env:RUNNER_TEMP\win32\cf8_installer.exe" + env: + SIGNING_KEY_WINDOWS_PASSPHRASE: ${{ secrets.SIGNING_KEY_WINDOWS_PASSPHRASE }} + + - name: View installer signature + run: | + Get-AuthenticodeSignature -Verbose -ErrorAction Stop "$env:RUNNER_TEMP\winx64\cf8_installer.exe" + Get-AuthenticodeSignature -Verbose -ErrorAction Stop "$env:RUNNER_TEMP\win32\cf8_installer.exe" + + - name: Arrange files for upload + # note the -Path flag takes comma-delimited args + run: | + Copy-Item -Destination "$env:RUNNER_TEMP\winx64" -Path .github\win\LICENSE,.github\win\NOTICE + Copy-Item -Destination "$env:RUNNER_TEMP\win32" -Path .github\win\LICENSE,.github\win\NOTICE + + - name: Zip windows artifact + run: | + # strip leading v to go from tag -> semver + $installer_release_version="$(cat BUILD_VERSION)".Replace("v", "") + pushd "$env:RUNNER_TEMP\winx64" + $installer_zip_filename="$env:RUNNER_TEMP\cf8-cli-installer_${installer_release_version}_winx64.zip" + Compress-Archive -DestinationPath "$installer_zip_filename" -Path * + popd + pushd "$env:RUNNER_TEMP\win32" + $installer_zip_filename="$env:RUNNER_TEMP\cf8-cli-installer_${installer_release_version}_win32.zip" + Compress-Archive -DestinationPath "$installer_zip_filename" -Path * + popd + Get-ChildItem "$env:RUNNER_TEMP" + + - name: Save installer and dist files as a GitHub Action Artifact + uses: actions/upload-artifact@v2 + with: + name: cf-cli-windows-packages + if-no-files-found: error + path: ${{ runner.temp }}/cf8-cli-installer*win*.zip + +################################# +######## Release Section ######## +################################# + + s3-upload: + name: Upload Artifacts to S3 bucket + if: ${{ github.ref_type == 'tag' }} + runs-on: ubuntu-latest + needs: + - test-rpm-package + - test-deb-package + - test-macos + - test-windows + environment: PROD + permissions: + actions: read + contents: read + steps: + - name: Checkout cli + uses: actions/checkout@v2 + - name: get semver version + # set environment var for subsequent steps. see: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-environment-variable + run: | + INSTALLER_RELEASE_VERSION=$(cat BUILD_VERSION | tr -d v) + echo "INSTALLER_RELEASE_VERSION=${INSTALLER_RELEASE_VERSION}" >> $GITHUB_ENV + + - name: Download signed artifacts + uses: actions/download-artifact@v2 + with: + path: signed # download all artifacts to 'signed/' + + - name: Archive linux binaries for upload + run: | + + prepare_legal() { + cp ../../.github/license/LICENSE-WITH-3RD-PARTY-LICENSES LICENSE + cp ../../.github/license/CF_NOTICE NOTICE + } + + prepare_artifacts() { + chmod +x cf8 + ln -s cf8 cf + prepare_legal + } + + prepare_win_artifacts() { + cp cf8.exe cf.exe + prepare_legal + } + + pushd signed + mkdir linux_i686 linux_x86-64 + mv cf-cli-linux-binaries/cf-cli_linux_i686 linux_i686/cf8 + mv cf-cli-linux-binaries/cf-cli_linux_x86-64 linux_x86-64/cf8 + pushd linux_i686 + prepare_artifacts + tar -cvzf cf8-cli_${INSTALLER_RELEASE_VERSION}_linux_i686.tgz * + popd + pushd linux_x86-64 + prepare_artifacts + tar -cvzf cf8-cli_${INSTALLER_RELEASE_VERSION}_linux_x86-64.tgz * + popd + + mkdir osx + mv cf-cli-macos-binaries/cf-cli_osx osx/cf8 + pushd osx + prepare_artifacts + tar -cvzf cf8-cli_${INSTALLER_RELEASE_VERSION}_osx.tgz * + popd + + mkdir win32 winx64 + mv cf-cli-windows-binaries/cf-cli_win32.exe win32/cf8.exe + mv cf-cli-windows-binaries/cf-cli_winx64.exe winx64/cf8.exe + pushd win32 + prepare_win_artifacts + # -y flag avoids the default behavior of derefencing the link, so we archive the symlink as-is + zip -y cf8-cli_${INSTALLER_RELEASE_VERSION}_win32.zip * + popd + pushd winx64 + prepare_win_artifacts + # -y flag avoids the default behavior of derefencing the link, so we archive the symlink as-is + zip -y cf8-cli_${INSTALLER_RELEASE_VERSION}_winx64.zip * + popd + popd + env: + INSTALLER_RELEASE_VERSION: ${{ env.INSTALLER_RELEASE_VERSION }} + + - name: Rearrange artifacts before upload + run: | + mkdir upload + cp -t upload \ + signed/cf-cli-linux-rpm-packages/cf*rpm \ + signed/cf-cli-linux-deb-packages/cf*deb \ + signed/cf-cli-macos-packages/cf*pkg \ + signed/cf-cli-windows-packages/cf*zip \ + signed/linux_i686/*tgz \ + signed/linux_x86-64/*tgz \ + signed/osx/*tgz \ + signed/win32/*zip \ + signed/winx64/*zip + + - name: Upload installers to CLAW S3 bucket + if: ${{ github.ref_type == 'tag' }} + # forked for security considerations + uses: pivotalsoftware/s3-sync-action@v0.5.2 #pinned to no-default-region change + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + SOURCE_DIR: upload + DEST_DIR: "releases/v${{ env.INSTALLER_RELEASE_VERSION }}" + + - name: list S3 for human verification + uses: docker://amazon/aws-cli:latest + with: + args: s3 ls "${{ env.AWS_S3_BUCKET }}/releases/v${{ env.INSTALLER_RELEASE_VERSION }}/" + env: + AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + INSTALLER_RELEASE_VERSION: ${{ env.INSTALLER_RELEASE_VERSION }} + + - name: Instruct human to update CLAW + run: | + echo "Please go to https://github.com/cloudfoundry/CLAW/blob/develop/claw-variables.yml and add the following line to the file:" + echo + echo "- ${INSTALLER_RELEASE_VERSION}" + + + + github-release-draft: + name: Create GitHub Release Draft + if: ${{ github.ref_type == 'tag' }} + runs-on: ubuntu-latest + environment: PROD + permissions: + actions: read + contents: write + needs: + - test-rpm-package + - test-deb-package + - test-macos + - test-windows + steps: + - name: Download signed artifacts + uses: actions/download-artifact@v2 + with: + path: signed # download all artifacts to 'signed/' + + - name: Create draft release + uses: pivotalsoftware/action-gh-release@v1 + with: + draft: true + repository: ${{ secrets.GIT_RELEASE_TARGET_REPO }} # repo to draft a release under, in / format + token: ${{ secrets.GIT_REPO_ACCESS_TOKEN }} # only needed when pushing to a repo other than 'self' + fail_on_unmatched_files: true + files: | + signed/cf-cli-linux-binaries/cf-cli* + signed/cf-cli-linux-deb-packages/cf*deb + signed/cf-cli-linux-rpm-packages/cf*rpm + signed/cf-cli-macos-binaries/cf-cli* + signed/cf-cli-macos-packages/cf*pkg + signed/cf-cli-windows-binaries/cf-cli*.exe + signed/cf-cli-windows-packages/*.zip + + +# vim: set sw=2 ts=2 sts=2 et tw=78 foldlevel=2 fdm=indent nospell: diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index eb0e0323d1b..e404f2dc45a 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -12,6 +12,7 @@ jobs: analyze: name: Analyze runs-on: ubuntu-latest + if: ${{ github.action_repository == 'cloudfoundry/cli' }} permissions: actions: read contents: read @@ -33,3 +34,5 @@ jobs: - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 + +# vim: set sw=2 ts=2 sts=2 et tw=78 foldlevel=2 fdm=indent nospell: diff --git a/.github/workflows/units.yml b/.github/workflows/units.yml index 5c6446e4f65..381e21aa522 100644 --- a/.github/workflows/units.yml +++ b/.github/workflows/units.yml @@ -13,101 +13,110 @@ defaults: shell: bash jobs: - lint: - name: Lint code + shared-values: + name: Shared Values runs-on: ubuntu-latest + outputs: + go-version: ${{ steps.set-go-version.outputs.go-version }} steps: - - - name: Checkout + - name: Checkout uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Set up Go - uses: actions/setup-go@v2 - with: - go-version: 1.17 - - - name: Run go fmt - run: go fmt && git diff --exit-code + - id: set-go-version + run: | + echo "::set-output name=go-version::1.17" - units-linux: - name: Units Linux + lint: + name: Lint code runs-on: ubuntu-latest + needs: shared-values steps: - - - name: Checkout + + - name: Checkout uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Set up Go + + - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.17 - - - name: Set up Test - run: | - go get -u github.com/onsi/ginkgo/ginkgo - go get github.com/onsi/gomega/matchers@v1.10.5 - - - name: Run Linux Units - run: make units - env: - ACK_GINKGO_RC: true + go-version: ${{ needs.shared-values.outputs.go-version }} + + - name: Run go fmt + run: go fmt && git diff --exit-code - units-macos: - name: Units OS X - runs-on: macos-latest + units: + name: Units + needs: shared-values + strategy: + matrix: + os: + - ubuntu-latest + - ubuntu-18.04 + - macos-latest + - macos-10.15 + runs-on: ${{ matrix.os }} steps: - - - name: Checkout + + - name: Checkout uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Set up Go + + - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.17 - - - name: Set up Test + go-version: ${{ needs.shared-values.outputs.go-version }} + + - name: Set up Test run: | go get -u github.com/onsi/ginkgo/ginkgo go get github.com/onsi/gomega/matchers@v1.10.5 - - - name: Run MacOS Units + + - name: Run Linux Units run: make units env: ACK_GINKGO_RC: true units-windows: name: Units Windows - runs-on: windows-latest + strategy: + matrix: + os: + - windows-2022 + - windows-2019 + - windows-2016 + runs-on: ${{ matrix.os }} + needs: shared-values + defaults: + run: + shell: pwsh steps: - - - name: Checkout + + - name: Checkout uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Set up Go + + - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.17 - - - name: Set up Test + go-version: ${{ needs.shared-values.outputs.go-version }} + + - name: Set up Test run: | go get -u github.com/onsi/ginkgo/ginkgo go get github.com/onsi/gomega/matchers@v1.10.5 - - - name: Run Windows Units - shell: pwsh + + - name: Get build-time dependencies + run: | + choco install --no-progress --limit-output -y make + + - name: Run Windows Units + env: + ACK_GINKGO_RC: true run: > + # Get-Command make + # Get-Item Makefile + # make units-non-plugin + ginkgo -r -p -randomizeAllSpecs -randomizeSuites -skipPackage integration,cf\ssh,plugin,cf\actors\plugin,cf\commands\plugin,cf\actors\plugin,util\randomword -flakeAttempts=2 - env: - ACK_GINKGO_RC: true + +# vim: set sw=2 ts=2 sts=2 et tw=78 foldlevel=2 fdm=indent nospell: diff --git a/.github/workflows/update-repos.yml b/.github/workflows/update-repos.yml new file mode 100644 index 00000000000..c12e52459a3 --- /dev/null +++ b/.github/workflows/update-repos.yml @@ -0,0 +1,416 @@ +name: Update Repositories + +on: + workflow_dispatch: + inputs: + build_version: + description: 'Build Version' + required: true + default: '8.3.0' + type: string + +permissions: + contents: write + +defaults: + run: + shell: bash + +jobs: + shared-values: + name: Setup + runs-on: ubuntu-latest + if: ${{ github.action_repository != 'cloudfoundry/cli' }} + outputs: + build-version: ${{ steps.set-build-version.outputs.build-version }} + secrets-environment: ${{ steps.set-secrets-environment.outputs.secrets-environment }} + steps: + + - name: Set environment + id: set-secrets-environment + run: echo "::set-output name=secrets-environment::PROD" + + - name: Checkout cli + uses: actions/checkout@v2 + + - name: Set build version + id: set-build-version + run: | + version=$(cat BUILD_VERSION) + echo "::set-output name=build-version::$version" + + update-homebrew: + name: Update Homebrew Repository + runs-on: ubuntu-latest + needs: shared-values + environment: ${{ needs.shared-values.outputs.secrets-environment }} + env: + BUILD_VERSION: ${{ needs.shared-values.outputs.build-version }} + steps: + + - name: Checkout cli-ci + uses: actions/checkout@v2 + with: + repository: cloudfoundry/cli-ci.git + ref: master + path: cli-ci + + - name: Checkout homebrew-tap + uses: actions/checkout@v2 + with: + repository: cloudfoundry/homebrew-tap + ref: master + path: homebrew-tap + ssh-key: ${{ secrets.GIT_DEPLOY_HOMEBREW_TAP }} + + - name: Setup + run: | + mkdir cf8-cli-osx-tarball cf8-cli-linux-tarball + + - name: Calculate checksums + run: | + set -x + + curl -L "https://packages.cloudfoundry.org/stable?release=macosx64-binary&version=${BUILD_VERSION}&source=github-rel" \ + > cf8-cli-osx-tarball/cf8-cli_${BUILD_VERSION}_osx.tgz + + # Because CLAW always returns 200 we have to check if we got archive + file cf8-cli-osx-tarball/cf8-cli_${BUILD_VERSION}_osx.tgz | grep -q gzip || exit 1 + + curl -L "https://packages.cloudfoundry.org/stable?release=linux64-binary&version=${BUILD_VERSION}&source=github-rel" \ + > cf8-cli-linux-tarball/cf8-cli_${BUILD_VERSION}_linux64.tgz + + # Because CLAW always returns 200 we have to check if we got archive + file cf8-cli-linux-tarball/cf8-cli_${BUILD_VERSION}_linux64.tgz | grep -q gzip || exit 1 + + pushd cf8-cli-osx-tarball + CLI_OSX_SHA256=$(shasum -a 256 cf8-cli_*_osx.tgz | cut -d ' ' -f 1) + popd + + pushd cf8-cli-linux-tarball + CLI_LINUX_64_SHA256=$(shasum -a 256 cf8-cli_*_linux64.tgz | cut -d ' ' -f 1) + popd + + echo "CLI_OSX_SHA256=${CLI_OSX_SHA256}" >> $GITHUB_ENV + echo "CLI_LINUX_64_SHA256=${CLI_LINUX_64_SHA256}" >> $GITHUB_ENV + + - name: Generate Homebrew formula file + run: | + set -ex + + pushd homebrew-tap + cat < cf-cli@8.rb + require 'formula' + + class CfCliAT8 < Formula + homepage 'https://code.cloudfoundry.org/cli' + version '${BUILD_VERSION}' + + if OS.mac? + url 'https://packages.cloudfoundry.org/homebrew/cf8-${BUILD_VERSION}.tgz' + sha256 '${CLI_OSX_SHA256}' + elsif OS.linux? + url 'https://packages.cloudfoundry.org/stable?release=linux64-binary&version=${BUILD_VERSION}&source=homebrew' + sha256 '${CLI_LINUX_64_SHA256}' + end + + depends_on :arch => :x86_64 + + def install + bin.install 'cf8' + bin.install_symlink 'cf8' => 'cf' + (bash_completion/"cf8-cli").write <<-completion + $(cat ../cli-ci/ci/installers/completion/cf8) + completion + doc.install 'LICENSE' + doc.install 'NOTICE' + end + + test do + system "#{bin}/cf8" + end + end + EOF + + popd + + - name: Commit new homebrew formula + run: | + pushd homebrew-tap + git add cf-cli@8.rb + + if ! [ -z "$(git status --porcelain)"]; then + git config user.name github-actions + git config user.email github-actions@github.com + git commit -m "Release CF CLI $BUILD_VERSION" + else + echo "no new version to commit" + fi + + git push + + echo "::group::cf-cli@8.rb" + cat cf-cli@8.rb + echo "::endgroup::" + + echo "::group::git show" + git show + echo "::endgroup::" + + popd + + test-homebrew: + name: Test Homebrew Repository + runs-on: macos-latest + needs: + - shared-values + - update-homebrew + environment: ${{ needs.shared-values.outputs.secrets-environment }} + env: + BUILD_VERSION: ${{ needs.shared-values.outputs.build-version }} + steps: + + - name: Install CF CLI via Homebrew + run: | + set -evx + + brew install cloudfoundry/tap/cf-cli@8 + installed_cf_version=$(cf8 version) + + cf_location=$(which cf) + + echo $cf_location + echo $installed_cf_version + echo $BUILD_VERSION + + codesign --verify $cf_location || echo --- + + cf -v | grep "$BUILD_VERSION" + + update-deb: + name: Update Debian Repository + runs-on: ubuntu-latest + needs: shared-values + environment: ${{ needs.shared-values.outputs.secrets-environment }} + env: + BUILD_VERSION: ${{ needs.shared-values.outputs.build-version }} + AWS_BUCKET_NAME: cf-cli-debian-repo + AWS_DEFAULT_REGION: us-west-2 + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + steps: + + - name: Setup + run: | + echo "BUILD_VERSION: $BUILD_VERSION" + echo "Environment: $ENVIRONMENT" + + - name: Checkout + uses: actions/checkout@v2 + + - uses: actions/checkout@v2 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.3 + - run: gem install deb-s3 + #RUN apt install -y ruby1.9.1 createrepo + + - name: Load GPG key + env: + SIGNING_KEY_GPG: ${{ secrets.SIGNING_KEY_GPG }} + SIGNING_KEY_GPG_PASSPHRASE: ${{ secrets.SIGNING_KEY_GPG_PASSPHRASE }} + run: | + echo -n "$SIGNING_KEY_GPG" | base64 --decode | gpg --no-tty --batch --pinentry-mode loopback --import + + - name: View GPG keys + run: gpg --list-keys + + - name: Configure GPG + run: | + echo "Configure GPG" + + # mkdir gpg-dir + # export GNUPGHOME=$PWD/gpg-dir + # chmod 700 $GNUPGHOME + # TODO: restore + # trap "rm -rf $GNUPGHOME" 0 + + cat >> ~/gpg.conf < installers/cf8-cli-installer_${BUILD_VERSION}_i686.deb + curl -L "https://cli.run.pivotal.io/stable?release=debian64&version=${BUILD_VERSION}&source=github-rel" > installers/cf8-cli-installer_${BUILD_VERSION}_x86-64.deb + + - name: Update Debian Repository + env: + DEBIAN_FRONTEND: noninteractive + SIGNING_KEY_GPG_ID: ${{ secrets.SIGNING_KEY_GPG_ID }} + run: | + deb-s3 upload installers/*.deb \ + --preserve-versions \ + --bucket=${AWS_BUCKET_NAME} \ + --sign=${SIGNING_KEY_GPG_ID} + + test-deb: + name: Test Debian Repository + runs-on: ubuntu-latest + needs: + - shared-values + - update-deb + environment: ${{ needs.shared-values.outputs.secrets-environment }} + env: + BUILD_VERSION: ${{ needs.shared-values.outputs.build-version }} + steps: + + - name: Install CF CLI via apt + run: | + set -o pipefail -e + + sudo apt update + sudo apt install -y wget gnupg + + wget -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add - + echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list + + sudo apt update + sudo apt install -y cf8-cli + + which cf + + set -x + + cf -v + cf8 -v + + cf -v | grep "$BUILD_VERSION" + + update-rpm: + name: Update RPM Repository + runs-on: ubuntu-18.04 + environment: ${{ needs.shared-values.outputs.secrets-environment }} + needs: shared-values + env: + AWS_DEFAULT_REGION: us-east-1 + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + steps: + + - name: Setup + env: + BUILD_VERSION: ${{ github.event.inputs.build_version }} + ENVIRONMENT: ${{ github.event.inputs.environment }} + run: | + echo "BUILD_VERSION: $BUILD_VERSION" + echo "Environment: $ENVIRONMENT" + + # TODO: fix backup + # - name: Download current RPM repodata + # env: + # AWS_DEFAULT_REGION: us-east-1 + # AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + # AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + # uses: docker://amazon/aws-cli:latest + # with: + # args: > + # s3 cp --recursive + # s3://cf-cli-rpm-repo/ + # backup + # TODO: fix https://aws.amazon.com/premiumsupport/knowledge-center/s3-access-denied-listobjects-sync/ + # + # - name: List assets + # run: | + # ls -R + # + # - name: Backup current Linux RPM repodata + # uses: actions/upload-artifact@v2 + # with: + # if-no-files-found: error + # name: cf-cli-linux-rpm-repodata-backup + # path: backup + + - name: Install Linux Packages + run: > + sudo apt update && + sudo apt install -y --no-install-recommends + gnupg createrepo + + - name: Download V8 RPMs + uses: docker://amazon/aws-cli:latest + with: + args: > + s3 sync --exclude "*" --include "releases/*/*installer*.rpm" + s3://v8-cf-cli-releases . + + - name: Download V7 RPMs + uses: docker://amazon/aws-cli:latest + with: + args: > + s3 sync --exclude "*" --include "releases/*/*installer*.rpm" + s3://v7-cf-cli-releases . + + - name: Download V6 RPMs + uses: docker://amazon/aws-cli:latest + with: + args: > + s3 sync --exclude "*" --include "releases/*/*installer*.rpm" + s3://cf-cli-releases . + + - name: Sign repo + run: | + createrepo --checksum=sha . + + - name: List assets + run: | + ls -R + + - name: Store Linux RPM repodata + uses: actions/upload-artifact@v2 + with: + if-no-files-found: error + name: cf-cli-linux-rpm-repodata + path: repodata + + - name: Upload RPM repodata + uses: docker://amazon/aws-cli:latest + with: + args: > + s3 sync --delete + repodata + s3://cf-cli-rpm-repo/repodata + + test-rpm-repo: + name: Test RPM Repository + needs: + - shared-values + - update-rpm + runs-on: ubuntu-latest + container: + image: fedora + environment: ${{ needs.shared-values.outputs.secrets-environment }} + env: + BUILD_VERSION: ${{ needs.shared-values.outputs.build-version }} + steps: + + - name: Configure Custom CF Repository + run: | + curl -sL -o /etc/yum.repos.d/cloudfoundry-cli.repo \ + https://packages.cloudfoundry.org/fedora/cloudfoundry-cli.repo + + - name: Install cf8-cli package + run: dnf install -y cf8-cli + + - name: Print CF CLI Versions + run: | + cf -v + cf8 -v + + - name: Test Version Match + run: cf -v | grep -q "$BUILD_VERSION" + +# vim: set sw=2 ts=2 sts=2 et tw=78 foldlevel=2 fdm=indent nospell: diff --git a/.gitignore b/.gitignore index 85d8d090b19..bdd84341efc 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,8 @@ tmp/ .hg/ +.envrc + *.test /tags diff --git a/Makefile b/Makefile index 195d9286aa3..aa70bbe8001 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,3 @@ -SHELL := env PATH=$(PATH) /bin/bash CF_DIAL_TIMEOUT ?= 15 NODES ?= 10 PACKAGES ?= api actor command types util version integration/helpers @@ -17,15 +16,13 @@ REQUIRED_FOR_STATIC_BINARY =-a -tags "netgo" -installsuffix netgo GOSRC = $(shell find . -name "*.go" ! -name "*test.go" ! -name "*fake*" ! -path "./integration/*") UNAME_S := $(shell uname -s) - -TARGET = v7 SLOW_SPEC_THRESHOLD=120 -GINKGO_FLAGS=-r -randomizeAllSpecs -requireSuite -GINKGO_INT_FLAGS=$(GINKGO_FLAGS) -slowSpecThreshold $(SLOW_SPEC_THRESHOLD) +GINKGO_FLAGS ?= -r -randomizeAllSpecs -requireSuite +GINKGO_INT_FLAGS = $(GINKGO_FLAGS) -slowSpecThreshold $(SLOW_SPEC_THRESHOLD) ginkgo_int = ginkgo $(GINKGO_INT_FLAGS) -GINKGO_UNITS_FLAGS=$(GINKGO_FLAGS) -randomizeSuites -p +GINKGO_UNITS_FLAGS = $(GINKGO_FLAGS) -randomizeSuites -p ginkgo_units = ginkgo $(GINKGO_UNITS_FLAGS) GOFLAGS := -mod=mod @@ -88,7 +85,7 @@ integration-shared-experimental: build integration-cleanup ## Run experimental i ive: integration-versioned-experimental integration-experimental-versioned: integration-versioned-experimental integration-versioned-experimental: build integration-cleanup ## Run experimental integration tests that are specific to your CLI version - $(ginkgo_int) -nodes $(NODES) integration/$(TARGET)/experimental + $(ginkgo_int) -nodes $(NODES) integration/v7/experimental ig: integration-global integration-global: build integration-cleanup integration-shared-global integration-global-versioned ## Run all unparallelizable integration tests that make cross-cutting changes to their test CF foundation @@ -101,7 +98,7 @@ integration-shared-global: build integration-cleanup ## Serially run integration ivg: integration-versioned-global integration-global-versioned: integration-versioned-global integration-versioned-global: build integration-cleanup ## Serially run integration tests that make cross-cutting changes to their test CF foundation and are specific to your CLI version - $(ginkgo_int) integration/$(TARGET)/global + $(ginkgo_int) integration/v7/global ii: integration-isolated integration-isolated: build integration-cleanup integration-shared-isolated integration-isolated-versioned ## Run all parallel-enabled integration tests, both versioned and shared across versions @@ -121,14 +118,14 @@ integration-shared-performance: build integration-cleanup ivi: integration-versioned-isolated integration-isolated-versioned: integration-versioned-isolated integration-versioned-isolated: build integration-cleanup ## Run all parallel-enabled integration tests, both versioned and shared across versions - $(ginkgo_int) -nodes $(NODES) integration/$(TARGET)/isolated + $(ginkgo_int) -nodes $(NODES) integration/v7/isolated integration-plugin: build integration-cleanup ## Run all plugin-related integration tests $(ginkgo_int) -nodes $(NODES) integration/shared/plugin ip: integration-push integration-push: build integration-cleanup ## Run all push-related integration tests - $(ginkgo_int) -nodes $(NODES) integration/$(TARGET)/push + $(ginkgo_int) -nodes $(NODES) integration/v7/push integration-selfcontained: build $(ginkgo_int) -nodes $(NODES) integration/v7/selfcontained diff --git a/bin/bump-version b/bin/bump-version index 7bb7882877a..b4693dc4e90 100755 --- a/bin/bump-version +++ b/bin/bump-version @@ -1,13 +1,17 @@ #!/usr/bin/env bash -set -e +set -eo pipefail component=$1 +script_dir=$(dirname $0) +version_file="$script_dir/../BUILD_VERSION" -old_version=$(cat BUILD_VERSION) +old_version=$(cat $version_file) major=$(echo $old_version | cut -d'.' -f 1) minor=$(echo $old_version | cut -d'.' -f 2) -patch=$(echo $old_version | cut -d'.' -f 3) +patchAndSuffix=$(echo $old_version | cut -d'.' -f 3) +patch=$(echo $patchAndSuffix | cut -d'-' -f 1) +suffix=$(echo $patchAndSuffix | cut -s -d'-' -f 2) case "$component" in major ) @@ -28,14 +32,19 @@ case "$component" in exit 1 ;; esac +set -u version=$major.$minor.$patch +if [ ! -z "$suffix" ]; then + version="${version}-${suffix}" +fi + echo "Updating BUILD_VERSION file to $version" -echo $version > BUILD_VERSION +echo $version > $version_file echo "Committing change" git reset . -git add BUILD_VERSION +git add $version_file git commit -m "Bump version to $version" diff --git a/bin/generate-release-notes b/bin/generate-release-notes index f1aad7ebcc5..0d7d8649681 100755 --- a/bin/generate-release-notes +++ b/bin/generate-release-notes @@ -5,7 +5,7 @@ VERSION=$(cat BUILD_VERSION) cat <<-NOTES Package Manager Installation ---------- -- [apt-get, yum, homebrew](https://github.com/cloudfoundry/cli#installing-using-a-package-manager) +- [apt-get, yum, homebrew](https://github.com/cloudfoundry/cli#getting-started) Installers ---------- From b3bd35fd9f455b403f20f91ed85d9450f23fa933 Mon Sep 17 00:00:00 2001 From: Alexander Berezovsky Date: Fri, 20 May 2022 10:18:58 +0000 Subject: [PATCH 029/248] Bump version to 8.4.0 --- BUILD_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD_VERSION b/BUILD_VERSION index 2bf50aaf17a..a2f28f43be3 100644 --- a/BUILD_VERSION +++ b/BUILD_VERSION @@ -1 +1 @@ -8.3.0 +8.4.0 From 9184b5d35effcbaba1ecbc522292371c1af1c5f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristhian=20Pe=C3=B1a?= Date: Fri, 1 Apr 2022 00:50:04 -0500 Subject: [PATCH 030/248] Testing hydrabroker with new dependency versions --- integration/assets/hydrabroker/go.mod | 10 +-- integration/assets/hydrabroker/go.sum | 116 +++++++++++++++----------- 2 files changed, 71 insertions(+), 55 deletions(-) diff --git a/integration/assets/hydrabroker/go.mod b/integration/assets/hydrabroker/go.mod index 07eeb84c388..723d2eecd2e 100644 --- a/integration/assets/hydrabroker/go.mod +++ b/integration/assets/hydrabroker/go.mod @@ -3,10 +3,10 @@ module code.cloudfoundry.org/cli/integration/assets/hydrabroker go 1.13 require ( - github.com/go-playground/validator/v10 v10.2.0 - github.com/gorilla/mux v1.7.4 + github.com/go-playground/validator/v10 v10.8.0 + github.com/gorilla/mux v1.8.0 github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d - github.com/onsi/ginkgo v1.14.2 - github.com/onsi/gomega v1.10.3 - github.com/pivotal-cf/brokerapi/v7 v7.2.0 + github.com/onsi/ginkgo v1.16.4 + github.com/onsi/gomega v1.14.0 + github.com/pivotal-cf/brokerapi/v7 v7.5.0 ) diff --git a/integration/assets/hydrabroker/go.sum b/integration/assets/hydrabroker/go.sum index 46fe43d0297..1b9dca6ebcb 100644 --- a/integration/assets/hydrabroker/go.sum +++ b/integration/assets/hydrabroker/go.sum @@ -1,16 +1,15 @@ code.cloudfoundry.org/lager v1.1.1-0.20191008172124-a9afc05ee5be h1:rnGRgbKlOPKbI9N/PscJ78Ug5Iw+o1kE7aDW01V+0FM= code.cloudfoundry.org/lager v1.1.1-0.20191008172124-a9afc05ee5be/go.mod h1:O2sS7gKP3HM2iemG+EnwvyNQK7pTSC6Foi4QiMp9sSk= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40 h1:y4B3+GPxKlrigF1ha5FFErxK+sr6sWxQovRMzwMhejo= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/drewolson/testflight v1.0.0 h1:jgA0pHcFIPnXoBmyFzrdoR2ka4UvReMDsjYc7Jcvl80= github.com/drewolson/testflight v1.0.0/go.mod h1:t9oKuuEohRGLb80SWX+uxJHuhX98B7HnojqtW+Ryq30= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -20,29 +19,30 @@ github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8c github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-playground/validator/v10 v10.8.0 h1:1kAa0fCrnpv+QYdkdcRzrRM7AyYs5o8+jZdJCz9xj6k= +github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s= github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= -github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -53,102 +53,118 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.0.0-20160504234017-7cafcd837844/go.mod h1:sjUstKUATFIcff4qlB53Kml0wQPtJVc/3fWrmuUmcfA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.3/go.mod h1:1ftk08SazyElaaNvmqAfZWGwJzshjCfBXDLoQtPAMNk= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= -github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= -github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34= -github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= -github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ= +github.com/onsi/gomega v1.14.0 h1:ep6kpPVwmr/nTbklSx2nrLNSIO62DoYAhnPNIMhK8gI= +github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709 h1:zNBQb37RGLmJybyMcs983HfUfpkw9OTFD9tbBfAViHE= github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= -github.com/pivotal-cf/brokerapi/v7 v7.2.0 h1:LL/OS3H2p+K30YG1ppB7Fr1YFQ669My00icLkxYqdwU= -github.com/pivotal-cf/brokerapi/v7 v7.2.0/go.mod h1:5QRQ8vJmav91F+AvY5NA/QoDOq70XgBVxXKUK4N/cNE= +github.com/pivotal-cf/brokerapi/v7 v7.5.0 h1:l7kAjlTL4bGIkl2m4dljc1xqgQYbU+4BjJskfkUn6Vc= +github.com/pivotal-cf/brokerapi/v7 v7.5.0/go.mod h1:+z5BKkzLViNax5Q8S3Z6e6dkDpAJl4ZJIu9mP1fhyZM= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -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/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M= -golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db h1:9hRk1xeL9LTT3yX/941DqeBz87XgHAQuj+TbimYJuiw= -golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200301222351-066e0c02454c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= From 2855a1b812cd60f8e7e0f8eab9dbb3d277d83903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristhian=20Pe=C3=B1a?= Date: Wed, 18 May 2022 15:48:23 -0500 Subject: [PATCH 031/248] Ginkgo 2.0 bump --- .../database/database_suite_test.go | 2 +- .../hydrabroker/database/database_test.go | 2 +- integration/assets/hydrabroker/go.mod | 4 +-- integration/assets/hydrabroker/go.sum | 34 +++++++++++++++---- .../integrationtest_suite_test.go | 2 +- .../integrationtest/integrationtest_test.go | 2 +- .../assets/hydrabroker/store/bindings_test.go | 2 +- .../assets/hydrabroker/store/brokers_test.go | 2 +- .../hydrabroker/store/instances_test.go | 2 +- .../hydrabroker/store/store_suite_test.go | 2 +- 10 files changed, 38 insertions(+), 16 deletions(-) diff --git a/integration/assets/hydrabroker/database/database_suite_test.go b/integration/assets/hydrabroker/database/database_suite_test.go index 6b7d74ae096..1684cdaa541 100644 --- a/integration/assets/hydrabroker/database/database_suite_test.go +++ b/integration/assets/hydrabroker/database/database_suite_test.go @@ -3,7 +3,7 @@ package database_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/integration/assets/hydrabroker/database/database_test.go b/integration/assets/hydrabroker/database/database_test.go index 00faebd56e2..bdec5be2605 100644 --- a/integration/assets/hydrabroker/database/database_test.go +++ b/integration/assets/hydrabroker/database/database_test.go @@ -5,7 +5,7 @@ import ( "sync" . "code.cloudfoundry.org/cli/integration/assets/hydrabroker/database" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/integration/assets/hydrabroker/go.mod b/integration/assets/hydrabroker/go.mod index 723d2eecd2e..54b7532c26d 100644 --- a/integration/assets/hydrabroker/go.mod +++ b/integration/assets/hydrabroker/go.mod @@ -6,7 +6,7 @@ require ( github.com/go-playground/validator/v10 v10.8.0 github.com/gorilla/mux v1.8.0 github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d - github.com/onsi/ginkgo v1.16.4 - github.com/onsi/gomega v1.14.0 + github.com/onsi/ginkgo/v2 v2.1.4 + github.com/onsi/gomega v1.19.0 github.com/pivotal-cf/brokerapi/v7 v7.5.0 ) diff --git a/integration/assets/hydrabroker/go.sum b/integration/assets/hydrabroker/go.sum index 1b9dca6ebcb..f946e90acb4 100644 --- a/integration/assets/hydrabroker/go.sum +++ b/integration/assets/hydrabroker/go.sum @@ -5,6 +5,9 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4Yn github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40 h1:y4B3+GPxKlrigF1ha5FFErxK+sr6sWxQovRMzwMhejo= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= +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= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -38,12 +41,14 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s= github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.0.0-20160823170715-cfb55aafdaf3/go.mod h1:Bvhd+E3laJ0AVkG0c9rmtZcnhV0HQ3+c3YxxqTvc/gA= @@ -67,12 +72,16 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ= -github.com/onsi/gomega v1.14.0 h1:ep6kpPVwmr/nTbklSx2nrLNSIO62DoYAhnPNIMhK8gI= -github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709 h1:zNBQb37RGLmJybyMcs983HfUfpkw9OTFD9tbBfAViHE= github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= github.com/pivotal-cf/brokerapi/v7 v7.5.0 h1:l7kAjlTL4bGIkl2m4dljc1xqgQYbU+4BjJskfkUn6Vc= @@ -89,15 +98,18 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 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/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -107,11 +119,14 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -119,6 +134,7 @@ golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -126,19 +142,25 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/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-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 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= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200301222351-066e0c02454c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/integration/assets/hydrabroker/integrationtest/integrationtest_suite_test.go b/integration/assets/hydrabroker/integrationtest/integrationtest_suite_test.go index 4d20e0df1ca..ee9ae0bf350 100644 --- a/integration/assets/hydrabroker/integrationtest/integrationtest_suite_test.go +++ b/integration/assets/hydrabroker/integrationtest/integrationtest_suite_test.go @@ -3,7 +3,7 @@ package integrationtest_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/integration/assets/hydrabroker/integrationtest/integrationtest_test.go b/integration/assets/hydrabroker/integrationtest/integrationtest_test.go index 5653454e801..2da29948bb4 100644 --- a/integration/assets/hydrabroker/integrationtest/integrationtest_test.go +++ b/integration/assets/hydrabroker/integrationtest/integrationtest_test.go @@ -16,7 +16,7 @@ import ( "code.cloudfoundry.org/cli/integration/assets/hydrabroker/config" "code.cloudfoundry.org/cli/integration/assets/hydrabroker/resources" uuid2 "github.com/nu7hatch/gouuid" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gstruct" "github.com/pivotal-cf/brokerapi/v7/domain/apiresponses" diff --git a/integration/assets/hydrabroker/store/bindings_test.go b/integration/assets/hydrabroker/store/bindings_test.go index e610eca98d9..fcc02d5ea51 100644 --- a/integration/assets/hydrabroker/store/bindings_test.go +++ b/integration/assets/hydrabroker/store/bindings_test.go @@ -7,7 +7,7 @@ import ( "code.cloudfoundry.org/cli/integration/assets/hydrabroker/resources" "code.cloudfoundry.org/cli/integration/assets/hydrabroker/store" uuid "github.com/nu7hatch/gouuid" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) diff --git a/integration/assets/hydrabroker/store/brokers_test.go b/integration/assets/hydrabroker/store/brokers_test.go index e57d35fac14..3f3e9fd2dbd 100644 --- a/integration/assets/hydrabroker/store/brokers_test.go +++ b/integration/assets/hydrabroker/store/brokers_test.go @@ -2,7 +2,7 @@ package store_test import ( "code.cloudfoundry.org/cli/integration/assets/hydrabroker/config" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "code.cloudfoundry.org/cli/integration/assets/hydrabroker/store" diff --git a/integration/assets/hydrabroker/store/instances_test.go b/integration/assets/hydrabroker/store/instances_test.go index ff285be0526..f6ea556dca4 100644 --- a/integration/assets/hydrabroker/store/instances_test.go +++ b/integration/assets/hydrabroker/store/instances_test.go @@ -6,7 +6,7 @@ import ( "code.cloudfoundry.org/cli/integration/assets/hydrabroker/config" "code.cloudfoundry.org/cli/integration/assets/hydrabroker/resources" uuid "github.com/nu7hatch/gouuid" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "code.cloudfoundry.org/cli/integration/assets/hydrabroker/store" diff --git a/integration/assets/hydrabroker/store/store_suite_test.go b/integration/assets/hydrabroker/store/store_suite_test.go index aa685e16a72..e79bb60932b 100644 --- a/integration/assets/hydrabroker/store/store_suite_test.go +++ b/integration/assets/hydrabroker/store/store_suite_test.go @@ -3,7 +3,7 @@ package store_test import ( "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) From 0c5acc167ffeef45eb0019b88cb08b3e32a16206 Mon Sep 17 00:00:00 2001 From: Alexander Berezovsky Date: Wed, 1 Jun 2022 21:02:01 +0000 Subject: [PATCH 032/248] Add GHA capability to release Apple ARM Support other CLI major versions Major Build-Sign-Upload workflow refactor Co-authored-by: Shwetha Gururaj Co-authored-by: Juan Diego Gonzalez Signed-off-by: Juan Diego Gonzalez --- .github/workflows/build-sign-upload.yml | 657 +++++++++++++++--------- .github/workflows/update-repos.yml | 253 +++++---- Makefile | 4 +- bin/generate-release-notes | 16 +- 4 files changed, 586 insertions(+), 344 deletions(-) diff --git a/.github/workflows/build-sign-upload.yml b/.github/workflows/build-sign-upload.yml index 37bbdeaccdf..c914ad1a782 100644 --- a/.github/workflows/build-sign-upload.yml +++ b/.github/workflows/build-sign-upload.yml @@ -1,10 +1,49 @@ - name: Build-Sign-Upload +# List of env variables + +# GitHub Actions specific +# +# ACTIONS_RUNNER_DEBUG +# ACTIONS_STEP_DEBUG +# +# AWS credentials +# To upload artifacts to S3 for CLAW +# +# AWS_ACCESS_KEY_ID +# AWS_REGION +# AWS_S3_BUCKET +# AWS_SECRET_ACCESS_KEY +# +# GitHub details +# To publish release draft +# +# GIT_DEPLOY_HOMEBREW_TAP +# GIT_RELEASE_TARGET_REPO +# GIT_REPO_ACCESS_TOKEN +# +# Signing keys +# +# SIGNING_KEY_GPG +# SIGNING_KEY_GPG_ID +# SIGNING_KEY_GPG_PASSPHRASE +# +# SIGNING_KEY_MAC_ID +# SIGNING_KEY_MAC_PASSPHRASE +# SIGNING_KEY_MAC_PFX +# +# SIGNING_KEY_WINDOWS_ID +# SIGNING_KEY_WINDOWS_PASSPHRASE +# SIGNING_KEY_WINDOWS_PFX + + on: push: tags: + - 'v7.*' - 'v8.*' + branches: + - "gh-actions-*" permissions: contents: read @@ -16,14 +55,47 @@ defaults: shell: bash jobs: + + # test: + # environment: DEV + # runs-on: ubuntu-latest + # steps: + # - name: Setup upterm session + # env: + # AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + # AWS_REGION: ${{ secrets.AWS_REGION }} + # AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + # AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + # GIT_RELEASE_TARGET_REPO: ${{ secrets.GIT_RELEASE_TARGET_REPO }} + # GIT_REPO_ACCESS_TOKEN: ${{ secrets.GIT_REPO_ACCESS_TOKEN }} + # SIGNING_KEY_GPG: ${{ secrets.SIGNING_KEY_GPG }} + # SIGNING_KEY_GPG_ID: ${{ secrets.SIGNING_KEY_GPG_ID }} + # SIGNING_KEY_GPG_PASSPHRASE: ${{ secrets.SIGNING_KEY_GPG_PASSPHRASE }} + # SIGNING_KEY_MAC_ID: ${{ secrets.SIGNING_KEY_MAC_ID }} + # SIGNING_KEY_MAC_PASSPHRASE: ${{ secrets.SIGNING_KEY_MAC_PASSPHRASE }} + # SIGNING_KEY_MAC_PFX: ${{ secrets.SIGNING_KEY_MAC_PFX }} + # SIGNING_KEY_WINDOWS_ID: ${{ secrets.SIGNING_KEY_WINDOWS_ID }} + # SIGNING_KEY_WINDOWS_PASSPHRASE: ${{ secrets.SIGNING_KEY_WINDOWS_PASSPHRASE }} + # SIGNING_KEY_WINDOWS_PFX: ${{ secrets.SIGNING_KEY_WINDOWS_PFX }} + # SIGNING_TEST_CA_MAC: ${{ secrets.SIGNING_TEST_CA_MAC }} + # if: always() + # uses: lhotari/action-upterm@v1 + # timeout-minutes: 60 + setup: name: Setup + # needs: test runs-on: ubuntu-latest if: ${{ github.action_repository != 'cloudfoundry/cli' }} outputs: secrets-environment: ${{ steps.set-secrets-environment.outputs.secrets-environment }} - build-version: ${{ steps.set-build-version.outputs.build-version }} - go-version: ${{ steps.set-go-version.outputs.go-version }} + go-version: ${{ steps.set-go-version.outputs.go-version }} + + version-build: ${{ steps.parse-semver.outputs.version-build }} + version-major: ${{ steps.parse-semver.outputs.version-major }} + version-minor: ${{ steps.parse-semver.outputs.version-minor }} + version-patch: ${{ steps.parse-semver.outputs.version-patch }} + steps: # note the key must be 'id' and not 'name' here, to be accessed via the steps. syntax above @@ -34,18 +106,26 @@ jobs: - name: Checkout cli uses: actions/checkout@v2 - - name: Check if BUILD_VERSION matches tag ${{ github.ref }} + - name: Check if VERSION_BUILD matches tag ${{ github.ref }} run: | echo "Git Ref: ${{ github.ref }}" - echo "BUILD_VERSION: $(cat BUILD_VERSION)" + echo "VERSION_BUILD: $(cat BUILD_VERSION)" exit 0 - - name: Set build version - id: set-build-version + - name: Parse semver + id: parse-semver run: | - version=$(cat BUILD_VERSION) - echo "::set-output name=build-version::$version" + VERSION=$(cat BUILD_VERSION) + VERSION="${VERSION#[vV]}" + + VERSION_MINOR="${VERSION#*.}" + VERSION_MINOR="${VERSION_MINOR%.*}" + + echo "::set-output name=version-build::${VERSION}" + echo "::set-output name=version-major::${VERSION%%\.*}" + echo "::set-output name=version-minor::${VERSION_MINOR}" + echo "::set-output name=version-patch::${VERSION##*.}" - name: Set go version id: set-go-version @@ -59,96 +139,6 @@ jobs: # uses: lhotari/action-upterm@v1 # timeout-minutes: 60 - test-rpm-package: - name: Test RPM Artifacts - needs: build-linux - runs-on: ubuntu-latest - container: - image: fedora - steps: - - - name: Download Signed Linux Packages - uses: actions/download-artifact@v2 - with: - name: cf-cli-linux-rpm-packages - - - name: Display structure of downloaded files - run: ls -R - - - name: Test RPMs - run: | - rpm -q --qf 'FN:\t%{FILENAMES}\nNAME:\t%{NAME}\nPGP:\t%{SIGPGP:pgpsig}\nGPG:\t%{SIGGPG:pgpsig}\n' -p *.rpm - - test-deb-package: - name: Test Debian Artifacts - needs: build-linux - runs-on: ubuntu-latest - container: - image: ubuntu - steps: - - - name: Download Signed Linux Packages - uses: actions/download-artifact@v2 - with: - name: cf-cli-linux-deb-packages - - - name: Display structure of downloaded files - run: | - ls -R - ls *.deb | xargs -n1 dpkg --info - - test-macos: - name: Test macOS Artifacts - needs: build-macos - runs-on: macos-latest - steps: - - - name: Download Signed macOS Packages - uses: actions/download-artifact@v2 - with: - name: cf-cli-macos-packages - - - name: Inspect macOS packages - run: | - ls -R - pkgutil --check-signature * - - test-windows: - name: Test Windows Artifacts - needs: build-windows - runs-on: windows-latest - defaults: - run: - shell: pwsh - steps: - - - name: Download Signed Windows Binaries - uses: actions/download-artifact@v2 - with: - name: cf-cli-windows-binaries - - - name: Inspect Windows packages - run: | - Get-AuthenticodeSignature -Verbose -ErrorAction Stop .\cf-cli_win32.exe - Get-AuthenticodeSignature -Verbose -ErrorAction Stop .\cf-cli_winx64.exe - - - name: Download Signed Windows Binaries - uses: actions/download-artifact@v2 - with: - name: cf-cli-windows-packages - - - name: Inspect Windows files - run: | - Get-ChildItem -Force - - - name: View installer signature - run: | - Expand-Archive -DestinationPath winx64 -Path cf8-cli-installer_*_winx64.zip - Expand-Archive -DestinationPath win32 -Path cf8-cli-installer_*_win32.zip - - Get-AuthenticodeSignature -Verbose -ErrorAction Stop ".\winx64\cf8_installer.exe" - Get-AuthenticodeSignature -Verbose -ErrorAction Stop ".\win32\cf8_installer.exe" - build-linux: name: Build Linux needs: @@ -157,13 +147,14 @@ jobs: environment: ${{ needs.setup.outputs.secrets-environment }} env: - BUILD_VERSION: ${{ needs.setup.outputs.build-version }} + VERSION_BUILD: ${{ needs.setup.outputs.version-build }} + VERSION_MAJOR: ${{ needs.setup.outputs.version-major }} steps: - name: Get Build Version id: get_build_version - run: echo "BUILD_VERSION $BUILD_VERSION" + run: echo "VERSION_BUILD $VERSION_BUILD" - name: Checkout cli uses: actions/checkout@v2 @@ -224,21 +215,21 @@ jobs: $SIGNING_KEY_GPG_ID EOF - RPM_VERSION=${BUILD_VERSION//-/_} + RPM_VERSION=${VERSION_BUILD//-/_} mkdir -pv $root/packaged echo "Build 32-bit RedHat package" ( pushd cli-ci/ci/installers/rpm - cp $root/out/cf-cli_linux_i686 cf8 - cp ../../license/NOTICE . - cp ../../license/LICENSE-WITH-3RD-PARTY-LICENSES LICENSE - cp ../completion/cf8 cf8.bash - echo "Version: ${RPM_VERSION}" > cf-cli.spec - cat cf8-cli.spec.template >> cf-cli.spec - rpmbuild --target i386 --define "_topdir $(pwd)/build" -bb cf-cli.spec - mv build/RPMS/i386/cf8-cli*.rpm $root/packaged/cf8-cli-installer_${BUILD_VERSION}_i686.rpm + cp $root/out/cf-cli_linux_i686 cf${VERSION_MAJOR} + cp ../../license/NOTICE . + cp ../../license/LICENSE-WITH-3RD-PARTY-LICENSES LICENSE + cp ../completion/cf${VERSION_MAJOR} cf${VERSION_MAJOR}.bash + echo "Version: ${RPM_VERSION}" > cf-cli.spec + cat cf${VERSION_MAJOR}-cli.spec.template >> cf-cli.spec + rpmbuild --target i386 --define "_topdir $(pwd)/build" -bb cf-cli.spec + mv build/RPMS/i386/cf${VERSION_MAJOR}-cli*.rpm $root/packaged/cf${VERSION_MAJOR}-cli-installer_${VERSION_BUILD}_i686.rpm popd ) @@ -246,14 +237,14 @@ jobs: echo "Build 64-bit RedHat package" ( pushd cli-ci/ci/installers/rpm - cp $root/out/cf-cli_linux_x86-64 cf8 - cp ../../license/NOTICE . - cp ../../license/LICENSE-WITH-3RD-PARTY-LICENSES LICENSE - cp ../completion/cf8 cf8.bash - echo "Version: ${RPM_VERSION}" > cf-cli.spec - cat cf8-cli.spec.template >> cf-cli.spec - rpmbuild --target x86_64 --define "_topdir $(pwd)/build" -bb cf-cli.spec - mv build/RPMS/x86_64/cf8-cli*.rpm $root/packaged/cf8-cli-installer_${BUILD_VERSION}_x86-64.rpm + cp $root/out/cf-cli_linux_x86-64 cf${VERSION_MAJOR} + cp ../../license/NOTICE . + cp ../../license/LICENSE-WITH-3RD-PARTY-LICENSES LICENSE + cp ../completion/cf${VERSION_MAJOR} cf${VERSION_MAJOR}.bash + echo "Version: ${RPM_VERSION}" > cf-cli.spec + cat cf${VERSION_MAJOR}-cli.spec.template >> cf-cli.spec + rpmbuild --target x86_64 --define "_topdir $(pwd)/build" -bb cf-cli.spec + mv build/RPMS/x86_64/cf${VERSION_MAJOR}-cli*.rpm $root/packaged/cf${VERSION_MAJOR}-cli-installer_${VERSION_BUILD}_x86-64.rpm popd ) @@ -269,23 +260,27 @@ jobs: - name: Sign RedHat Packages env: - SIGNING_KEY_GPG_ID: ${{ secrets.SIGNING_KEY_GPG_ID }} + SIGNING_KEY_GPG_ID: ${{ secrets.SIGNING_KEY_GPG_ID }} SIGNING_KEY_GPG_PASSPHRASE: ${{ secrets.SIGNING_KEY_GPG_PASSPHRASE }} run: | set -ex set -o pipefail - SUFFIX=8 - mkdir signed-redhat-installer cat<< EOF >~/.rpmmacros + %_signature gpg %_gpg_name $SIGNING_KEY_GPG_ID + %_gpgbin /usr/bin/gpg2 + %__gpg_sign_cmd %{__gpg} gpg --force-v3-sigs --batch --verbose --no-armor \ + --passphrase "$SIGNING_KEY_GPG_PASSPHRASE" --no-secmem-warning -u "%{_gpg_name}" \ + -sbo %{__signature_filename} --digest-algo sha256 %{__plaintext_filename} EOF cp packaged/cf*.rpm signed-redhat-installer/ - # TODO: consider to add --key-id + #TODO: consider to add --key-id + #TODO: DEV shim rpmsign --addsign signed-redhat-installer/*.rpm - name: Print RPM Signature @@ -301,6 +296,9 @@ jobs: - name: Build Debian Packages + env: + VERSION_BUILD: ${{ needs.setup.outputs.version-build }} + VERSION_MAJOR: ${{ needs.setup.outputs.version-major }} run: | set -ex set -o pipefail @@ -314,30 +312,30 @@ jobs: SIZE="$(BLOCKSIZE=1000 du $root/out/cf-cli_linux_i686 | cut -f 1)" pushd cli-ci/ci/installers/deb - mkdir -p cf/usr/bin cf/usr/share/doc/cf8-cli/ cf/DEBIAN cf/usr/share/bash-completion/completions + mkdir -p cf/usr/bin cf/usr/share/doc/cf${VERSION_MAJOR}-cli/ cf/DEBIAN cf/usr/share/bash-completion/completions cp copyright_preamble cf/DEBIAN/copyright sed 's/^$/ ./' $root/LICENSE >> cf/DEBIAN/copyright cat copyright_comment_header >> cf/DEBIAN/copyright sed 's/^$/ ./' ../../license/3RD-PARTY-LICENSES >> cf/DEBIAN/copyright - cp cf/DEBIAN/copyright cf/usr/share/doc/cf8-cli/copyright + cp cf/DEBIAN/copyright cf/usr/share/doc/cf${VERSION_MAJOR}-cli/copyright - cp ../../license/NOTICE cf/usr/share/doc/cf8-cli - cp ../../license/LICENSE-WITH-3RD-PARTY-LICENSES cf/usr/share/doc/cf8-cli/LICENSE + cp ../../license/NOTICE cf/usr/share/doc/cf${VERSION_MAJOR}-cli + cp ../../license/LICENSE-WITH-3RD-PARTY-LICENSES cf/usr/share/doc/cf${VERSION_MAJOR}-cli/LICENSE cp control_v8.template cf/DEBIAN/control echo "Installed-Size: ${SIZE}" >> cf/DEBIAN/control - echo "Version: ${BUILD_VERSION}" >> cf/DEBIAN/control + echo "Version: ${VERSION_BUILD}" >> cf/DEBIAN/control echo "Architecture: i386" >> cf/DEBIAN/control - cp ../completion/cf8 cf/usr/share/bash-completion/completions/cf8 + cp ../completion/cf${VERSION_MAJOR} cf/usr/share/bash-completion/completions/cf${VERSION_MAJOR} - cp $root/out/cf-cli_linux_i686 cf/usr/bin/cf8 - ln -frs cf/usr/bin/cf8 cf/usr/bin/cf + cp $root/out/cf-cli_linux_i686 cf/usr/bin/cf${VERSION_MAJOR} + ln -frs cf/usr/bin/cf${VERSION_MAJOR} cf/usr/bin/cf - fakeroot dpkg --build cf cf8-cli-installer_${BUILD_VERSION}_i686.deb - mv cf8-cli-installer_${BUILD_VERSION}_i686.deb $root/packaged-deb + fakeroot dpkg --build cf cf${VERSION_MAJOR}-cli-installer_${VERSION_BUILD}_i686.deb + mv cf${VERSION_MAJOR}-cli-installer_${VERSION_BUILD}_i686.deb $root/packaged-deb rm -rf cf popd ) @@ -347,30 +345,30 @@ jobs: SIZE="$(BLOCKSIZE=1000 du $root/out/cf-cli_linux_x86-64 | cut -f 1)" pushd cli-ci/ci/installers/deb - mkdir -p cf/usr/bin cf/usr/share/doc/cf8-cli/ cf/DEBIAN cf/usr/share/bash-completion/completions + mkdir -p cf/usr/bin cf/usr/share/doc/cf${VERSION_MAJOR}-cli/ cf/DEBIAN cf/usr/share/bash-completion/completions cp copyright_preamble cf/DEBIAN/copyright sed 's/^$/ ./' $root/LICENSE >> cf/DEBIAN/copyright cat copyright_comment_header >> cf/DEBIAN/copyright sed 's/^$/ ./' ../../license/3RD-PARTY-LICENSES >> cf/DEBIAN/copyright - cp cf/DEBIAN/copyright cf/usr/share/doc/cf8-cli/copyright + cp cf/DEBIAN/copyright cf/usr/share/doc/cf${VERSION_MAJOR}-cli/copyright - cp ../../license/NOTICE cf/usr/share/doc/cf8-cli - cp ../../license/LICENSE-WITH-3RD-PARTY-LICENSES cf/usr/share/doc/cf8-cli/LICENSE + cp ../../license/NOTICE cf/usr/share/doc/cf${VERSION_MAJOR}-cli + cp ../../license/LICENSE-WITH-3RD-PARTY-LICENSES cf/usr/share/doc/cf${VERSION_MAJOR}-cli/LICENSE cp control_v8.template cf/DEBIAN/control echo "Installed-Size: ${SIZE}" >> cf/DEBIAN/control - echo "Version: ${BUILD_VERSION}" >> cf/DEBIAN/control + echo "Version: ${VERSION_BUILD}" >> cf/DEBIAN/control echo "Architecture: amd64" >> cf/DEBIAN/control - cp ../completion/cf8 cf/usr/share/bash-completion/completions/cf8 + cp ../completion/cf${VERSION_MAJOR} cf/usr/share/bash-completion/completions/cf${VERSION_MAJOR} - cp $root/out/cf-cli_linux_x86-64 cf/usr/bin/cf8 - ln -frs cf/usr/bin/cf8 cf/usr/bin/cf + cp $root/out/cf-cli_linux_x86-64 cf/usr/bin/cf${VERSION_MAJOR} + ln -frs cf/usr/bin/cf${VERSION_MAJOR} cf/usr/bin/cf - fakeroot dpkg --build cf cf8-cli-installer_${BUILD_VERSION}_x86-64.deb - mv cf8-cli-installer_${BUILD_VERSION}_x86-64.deb $root/packaged-deb + fakeroot dpkg --build cf cf${VERSION_MAJOR}-cli-installer_${VERSION_BUILD}_x86-64.deb + mv cf${VERSION_MAJOR}-cli-installer_${VERSION_BUILD}_x86-64.deb $root/packaged-deb popd ) @@ -394,17 +392,20 @@ jobs: name: Build macOS needs: - setup + env: + VERSION_BUILD: ${{ needs.setup.outputs.version-build }} + VERSION_MAJOR: ${{ needs.setup.outputs.version-major }} runs-on: macos-latest environment: ${{ needs.setup.outputs.secrets-environment }} steps: - - name: Setup - run: | - echo "BUILD_VERSION=${{ needs.setup.outputs.build-version }}" >> $GITHUB_ENV + # - name: Setup + # run: | + # echo "VERSION_BUILD=${{ needs.setup.outputs.version-build }}" >> $GITHUB_ENV - name: Get Build Version id: get_build_version - run: echo "BUILD_VERSION $BUILD_VERSION" + run: echo "VERSION_BUILD $VERSION_BUILD" - name: Checkout cli uses: actions/checkout@v2 @@ -471,7 +472,7 @@ jobs: - name: Build macOS Binaries run: | make out/cf-cli_osx - make out/cf-cli_osx_arm + make out/cf-cli_macosarm - name: Store macOS Binaries uses: actions/upload-artifact@v2 @@ -480,7 +481,7 @@ jobs: name: cf-cli-macos-binaries path: out/cf-cli* - - name: Build macOS Installer + - name: Build macOS x86 Installer run: | set -ex set -o pipefail @@ -494,14 +495,49 @@ jobs: SIZE="$(BLOCKSIZE=1000 du $root/out/cf-cli_osx | cut -f 1)" pushd cli-ci/ci/installers/osx_v8 - sed -i -e "s/VERSION/${BUILD_VERSION}/g" Distribution + sed -i -e "s/VERSION/${VERSION_BUILD}/g" Distribution + sed -i -e "s/SIZE/${SIZE}/g" Distribution + mkdir -p cf-cli/usr/local/bin cf-cli/usr/local/share/doc/cf${VERSION_MAJOR}-cli + + cp $root/out/cf-cli_osx cf-cli/usr/local/bin/cf${VERSION_MAJOR} + gln -frs cf-cli/usr/local/bin/cf${VERSION_MAJOR} cf-cli/usr/local/bin/cf + cp ../../license/NOTICE cf-cli/usr/local/share/doc/cf${VERSION_MAJOR}-cli + cp ../../license/LICENSE-WITH-3RD-PARTY-LICENSES cf-cli/usr/local/share/doc/cf${VERSION_MAJOR}-cli/LICENSE + chmod -R go-w cf-cli + pushd cf-cli + find usr | cpio -o --format=odc | gzip -c > ../Payload + popd + + $root/bomutils/build/bin/ls4mkbom cf-cli | sed 's/1000\/1000/0\/80/' > bom_list + mkbom -i bom_list Bom + mv Bom Payload com.cloudfoundry.cf${VERSION_MAJOR}-cli.pkg + xar -c --compression none -f cf${VERSION_MAJOR}-cli-installer_osx.pkg com.cloudfoundry.cf${VERSION_MAJOR}-cli.pkg Distribution + mv cf${VERSION_MAJOR}-cli-installer_osx.pkg $root/packaged/cf${VERSION_MAJOR}-cli-installer_osx.pkg + popd + ) + + - name: Build macOS ARM Installer + run: | + set -ex + set -o pipefail + + root=$PWD + + mkdir -pv $root/packaged + + echo "Build macOS ARM Installer" + ( + SIZE="$(BLOCKSIZE=1000 du $root/out/cf-cli_macosarm | cut -f 1)" + + pushd cli-ci/ci/installers/osx_v8 + sed -i -e "s/VERSION/${VERSION_BUILD}/g" Distribution sed -i -e "s/SIZE/${SIZE}/g" Distribution - mkdir -p cf-cli/usr/local/bin cf-cli/usr/local/share/doc/cf8-cli + mkdir -p cf-cli/usr/local/bin cf-cli/usr/local/share/doc/cf${VERSION_MAJOR}-cli - cp $root/out/cf-cli_osx cf-cli/usr/local/bin/cf8 - gln -frs cf-cli/usr/local/bin/cf8 cf-cli/usr/local/bin/cf - cp ../../license/NOTICE cf-cli/usr/local/share/doc/cf8-cli - cp ../../license/LICENSE-WITH-3RD-PARTY-LICENSES cf-cli/usr/local/share/doc/cf8-cli/LICENSE + cp $root/out/cf-cli_macosarm cf-cli/usr/local/bin/cf${VERSION_MAJOR} + gln -frs cf-cli/usr/local/bin/cf${VERSION_MAJOR} cf-cli/usr/local/bin/cf + cp ../../license/NOTICE cf-cli/usr/local/share/doc/cf${VERSION_MAJOR}-cli + cp ../../license/LICENSE-WITH-3RD-PARTY-LICENSES cf-cli/usr/local/share/doc/cf${VERSION_MAJOR}-cli/LICENSE chmod -R go-w cf-cli pushd cf-cli find usr | cpio -o --format=odc | gzip -c > ../Payload @@ -509,21 +545,18 @@ jobs: $root/bomutils/build/bin/ls4mkbom cf-cli | sed 's/1000\/1000/0\/80/' > bom_list mkbom -i bom_list Bom - mv Bom Payload com.cloudfoundry.cf8-cli.pkg - xar -c --compression none -f cf8-cli-installer_osx.pkg com.cloudfoundry.cf8-cli.pkg Distribution - mv cf8-cli-installer_osx.pkg $root/packaged/cf8-cli-installer_osx.pkg + mv Bom Payload com.cloudfoundry.cf${VERSION_MAJOR}-cli.pkg + xar -c --compression none -f cf${VERSION_MAJOR}-cli-installer_macosarm.pkg com.cloudfoundry.cf${VERSION_MAJOR}-cli.pkg Distribution + mv cf${VERSION_MAJOR}-cli-installer_macosarm.pkg $root/packaged/cf${VERSION_MAJOR}-cli-installer_macosarm.pkg popd ) - name: Load macos key env: - SIGNING_TEST_CA_MAC: ${{ secrets.SIGNING_TEST_CA_MAC }} - SIGNING_KEYCHAIN_PASSPHRASE: ${{ secrets.SIGNING_KEYCHAIN_PASSPHRASE }} - - SIGNING_KEY_MAC: ${{ secrets.SIGNING_KEY_MAC }} - SIGNING_KEY_MAC_ID: ${{ secrets.SIGNING_KEY_MAC_ID }} + # SIGNING_TEST_CA_MAC: ${{ secrets.SIGNING_TEST_CA_MAC }} + SIGNING_KEY_MAC_ID: ${{ secrets.SIGNING_KEY_MAC_ID }} SIGNING_KEY_MAC_PASSPHRASE: ${{ secrets.SIGNING_KEY_MAC_PASSPHRASE }} - SIGNING_KEY_MAC_PFX: ${{ secrets.SIGNING_KEY_MAC_PFX }} + SIGNING_KEY_MAC_PFX: ${{ secrets.SIGNING_KEY_MAC_PFX }} run: | echo -n "$SIGNING_KEY_MAC_PFX" | base64 --decode > mac-signing-key.p12 @@ -558,26 +591,35 @@ jobs: - name: Sign macOS env: - SUFFIX: 8 - SIGNING_KEY_MAC_ID: ${{ secrets.SIGNING_KEY_MAC_ID }} + VERSION_MAJOR: ${{ needs.setup.outputs.version-major }} + SIGNING_KEY_MAC_ID: ${{ secrets.SIGNING_KEY_MAC_ID }} SIGNING_KEY_MAC_PASSPHRASE: ${{ secrets.SIGNING_KEY_MAC_PASSPHRASE }} run: | root=$PWD - mkdir -pv signed-osx-installer + mkdir -pv signed-macos-installer + + #TODO: DEV shim + # cp \ + productsign --timestamp \ + --sign "$SIGNING_KEY_MAC_ID" \ + "$root/packaged/cf${VERSION_MAJOR}-cli-installer_osx.pkg" \ + "signed-macos-installer/cf${VERSION_MAJOR}-cli-installer_${VERSION_BUILD}_osx.pkg" + #TODO: DEV shim + # cp \ productsign --timestamp \ --sign "$SIGNING_KEY_MAC_ID" \ - "$root/packaged/cf${SUFFIX}-cli-installer_osx.pkg" \ - "signed-osx-installer/cf${SUFFIX}-cli-installer_${BUILD_VERSION}_osx.pkg" + "$root/packaged/cf${VERSION_MAJOR}-cli-installer_macosarm.pkg" \ + "signed-macos-installer/cf${VERSION_MAJOR}-cli-installer_${VERSION_BUILD}_macosarm.pkg" - name: Store macOS Signed Packages uses: actions/upload-artifact@v2 with: if-no-files-found: error name: cf-cli-macos-packages - path: signed-osx-installer/*.pkg + path: signed-macos-installer/*.pkg build-windows: @@ -589,6 +631,8 @@ jobs: defaults: run: shell: pwsh + env: + VERSION_MAJOR: ${{ needs.setup.outputs.version-major }} steps: - name: Checkout uses: actions/checkout@v2 @@ -612,20 +656,20 @@ jobs: make out/cf-cli_winx64.exe - name: write windows cert - run: | - $pass = convertto-securestring -string "$env:SIGNING_KEY_WINDOWS_PASSPHRASE" -asplaintext - [convert]::frombase64string($env:SIGNING_KEY_WINDOWS_PFX) | set-content -path $env:runner_temp\cert.pfx -asbytestream - env: - SIGNING_KEY_WINDOWS_PFX: ${{ secrets.SIGNING_KEY_WINDOWS_PFX }} SIGNING_KEY_WINDOWS_PASSPHRASE: ${{ secrets.SIGNING_KEY_WINDOWS_PASSPHRASE }} + SIGNING_KEY_WINDOWS_PFX: ${{ secrets.SIGNING_KEY_WINDOWS_PFX }} + run: | + $pass = convertto-securestring -string "${env:SIGNING_KEY_WINDOWS_PASSPHRASE}" -asplaintext + [convert]::frombase64string(${env:SIGNING_KEY_WINDOWS_PFX}) | set-content -path $env:runner_temp\cert.pfx -asbytestream + - name: Sign windows binaries + env: + SIGNING_KEY_WINDOWS_PASSPHRASE: ${{ secrets.SIGNING_KEY_WINDOWS_PASSPHRASE }} run: | .\.github\win\sign-windows-binary.ps1 -BinaryFilePath out\cf-cli_win32.exe .\.github\win\sign-windows-binary.ps1 -BinaryFilePath out\cf-cli_winx64.exe - env: - SIGNING_KEY_WINDOWS_PASSPHRASE: ${{ secrets.SIGNING_KEY_WINDOWS_PASSPHRASE }} - name: View binary signatures run: | @@ -667,49 +711,52 @@ jobs: - name: Run innosetup run: | - mkdir "$env:RUNNER_TEMP\winx64" - .\.github\win\run-innosetup.ps1 -InnoSetupConfig ".github\win\windows-installer-v8-x64.iss" -CfBinary "out\cf-cli_winx64.exe" -InstallerOutput "$env:RUNNER_TEMP\winx64\cf8_installer.exe" - mkdir "$env:RUNNER_TEMP\win32" - .\.github\win\run-innosetup.ps1 -InnoSetupConfig ".github\win\windows-installer-v8-x86.iss" -CfBinary "out\cf-cli_win32.exe" -InstallerOutput "$env:RUNNER_TEMP\win32\cf8_installer.exe" + mkdir "${env:RUNNER_TEMP}\winx64" + .\.github\win\run-innosetup.ps1 -InnoSetupConfig ".github\win\windows-installer-v8-x64.iss" -CfBinary "out\cf-cli_winx64.exe" -InstallerOutput "${env:RUNNER_TEMP}\winx64\cf${env:VERSION_MAJOR}_installer.exe" + mkdir "${env:RUNNER_TEMP}\win32" + .\.github\win\run-innosetup.ps1 -InnoSetupConfig ".github\win\windows-installer-v8-x86.iss" -CfBinary "out\cf-cli_win32.exe" -InstallerOutput "${env:RUNNER_TEMP}\win32\cf${env:VERSION_MAJOR}_installer.exe" - name: Sign windows installer - run: | - .\.github\win\sign-windows-binary.ps1 -BinaryFilePath "$env:RUNNER_TEMP\winx64\cf8_installer.exe" - .\.github\win\sign-windows-binary.ps1 -BinaryFilePath "$env:RUNNER_TEMP\win32\cf8_installer.exe" env: SIGNING_KEY_WINDOWS_PASSPHRASE: ${{ secrets.SIGNING_KEY_WINDOWS_PASSPHRASE }} + run: | + .\.github\win\sign-windows-binary.ps1 -BinaryFilePath "${env:RUNNER_TEMP}\winx64\cf${env:VERSION_MAJOR}_installer.exe" + .\.github\win\sign-windows-binary.ps1 -BinaryFilePath "${env:RUNNER_TEMP}\win32\cf${env:VERSION_MAJOR}_installer.exe" - name: View installer signature run: | - Get-AuthenticodeSignature -Verbose -ErrorAction Stop "$env:RUNNER_TEMP\winx64\cf8_installer.exe" - Get-AuthenticodeSignature -Verbose -ErrorAction Stop "$env:RUNNER_TEMP\win32\cf8_installer.exe" + Get-AuthenticodeSignature -Verbose -ErrorAction Stop "${env:RUNNER_TEMP}\winx64\cf${env:VERSION_MAJOR}_installer.exe" + Get-AuthenticodeSignature -Verbose -ErrorAction Stop "${env:RUNNER_TEMP}\win32\cf${env:VERSION_MAJOR}_installer.exe" - name: Arrange files for upload # note the -Path flag takes comma-delimited args run: | - Copy-Item -Destination "$env:RUNNER_TEMP\winx64" -Path .github\win\LICENSE,.github\win\NOTICE - Copy-Item -Destination "$env:RUNNER_TEMP\win32" -Path .github\win\LICENSE,.github\win\NOTICE + Copy-Item -Destination "${env:RUNNER_TEMP}\winx64" -Path .github\win\LICENSE,.github\win\NOTICE + Copy-Item -Destination "${env:RUNNER_TEMP}\win32" -Path .github\win\LICENSE,.github\win\NOTICE - name: Zip windows artifact run: | # strip leading v to go from tag -> semver $installer_release_version="$(cat BUILD_VERSION)".Replace("v", "") - pushd "$env:RUNNER_TEMP\winx64" - $installer_zip_filename="$env:RUNNER_TEMP\cf8-cli-installer_${installer_release_version}_winx64.zip" + pushd "${env:RUNNER_TEMP}\winx64" + $installer_zip_filename="${env:RUNNER_TEMP}\cf${env:VERSION_MAJOR}-cli-installer_${installer_release_version}_winx64.zip" Compress-Archive -DestinationPath "$installer_zip_filename" -Path * popd - pushd "$env:RUNNER_TEMP\win32" - $installer_zip_filename="$env:RUNNER_TEMP\cf8-cli-installer_${installer_release_version}_win32.zip" + pushd "${env:RUNNER_TEMP}\win32" + $installer_zip_filename="${env:RUNNER_TEMP}\cf${env:VERSION_MAJOR}-cli-installer_${installer_release_version}_win32.zip" Compress-Archive -DestinationPath "$installer_zip_filename" -Path * popd - Get-ChildItem "$env:RUNNER_TEMP" + Get-ChildItem "${env:RUNNER_TEMP}" + + # - name: Setup tmate session + # uses: mxschmitt/action-tmate@v3 - name: Save installer and dist files as a GitHub Action Artifact uses: actions/upload-artifact@v2 with: name: cf-cli-windows-packages if-no-files-found: error - path: ${{ runner.temp }}/cf8-cli-installer*win*.zip + path: ${{ runner.temp }}/cf${{ needs.setup.outputs.version-major }}-cli-installer*win*.zip ################################# ######## Release Section ######## @@ -717,20 +764,25 @@ jobs: s3-upload: name: Upload Artifacts to S3 bucket - if: ${{ github.ref_type == 'tag' }} runs-on: ubuntu-latest needs: - - test-rpm-package - - test-deb-package - - test-macos - - test-windows - environment: PROD + - setup + - test-rpm-package + - test-deb-package + - test-macos + - test-windows + environment: ${{ needs.setup.outputs.secrets-environment }} permissions: actions: read contents: read + env: + VERSION_BUILD: ${{ needs.setup.outputs.version-build }} + VERSION_MAJOR: ${{ needs.setup.outputs.version-major }} steps: + - name: Checkout cli uses: actions/checkout@v2 + - name: get semver version # set environment var for subsequent steps. see: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-environment-variable run: | @@ -742,7 +794,9 @@ jobs: with: path: signed # download all artifacts to 'signed/' - - name: Archive linux binaries for upload + - name: Archive nix binaries for upload + env: + INSTALLER_RELEASE_VERSION: ${{ env.INSTALLER_RELEASE_VERSION }} run: | prepare_legal() { @@ -751,57 +805,62 @@ jobs: } prepare_artifacts() { - chmod +x cf8 - ln -s cf8 cf + chmod +x cf${VERSION_MAJOR} + ln -s cf${VERSION_MAJOR} cf prepare_legal } prepare_win_artifacts() { - cp cf8.exe cf.exe + cp cf${VERSION_MAJOR}.exe cf.exe prepare_legal } pushd signed mkdir linux_i686 linux_x86-64 - mv cf-cli-linux-binaries/cf-cli_linux_i686 linux_i686/cf8 - mv cf-cli-linux-binaries/cf-cli_linux_x86-64 linux_x86-64/cf8 + mv cf-cli-linux-binaries/cf-cli_linux_i686 linux_i686/cf${VERSION_MAJOR} + mv cf-cli-linux-binaries/cf-cli_linux_x86-64 linux_x86-64/cf${VERSION_MAJOR} pushd linux_i686 prepare_artifacts - tar -cvzf cf8-cli_${INSTALLER_RELEASE_VERSION}_linux_i686.tgz * + tar -cvzf cf${VERSION_MAJOR}-cli_${INSTALLER_RELEASE_VERSION}_linux_i686.tgz * popd pushd linux_x86-64 prepare_artifacts - tar -cvzf cf8-cli_${INSTALLER_RELEASE_VERSION}_linux_x86-64.tgz * + tar -cvzf cf${VERSION_MAJOR}-cli_${INSTALLER_RELEASE_VERSION}_linux_x86-64.tgz * popd mkdir osx - mv cf-cli-macos-binaries/cf-cli_osx osx/cf8 + mv cf-cli-macos-binaries/cf-cli_osx osx/cf${VERSION_MAJOR} pushd osx prepare_artifacts - tar -cvzf cf8-cli_${INSTALLER_RELEASE_VERSION}_osx.tgz * + tar -cvzf cf${VERSION_MAJOR}-cli_${INSTALLER_RELEASE_VERSION}_osx.tgz * + popd + + mkdir macosarm + mv cf-cli-macos-binaries/cf-cli_macosarm macosarm/cf${VERSION_MAJOR} + pushd macosarm + prepare_artifacts + tar -cvzf cf${VERSION_MAJOR}-cli_${INSTALLER_RELEASE_VERSION}_macosarm.tgz * popd mkdir win32 winx64 - mv cf-cli-windows-binaries/cf-cli_win32.exe win32/cf8.exe - mv cf-cli-windows-binaries/cf-cli_winx64.exe winx64/cf8.exe + mv cf-cli-windows-binaries/cf-cli_win32.exe win32/cf${VERSION_MAJOR}.exe + mv cf-cli-windows-binaries/cf-cli_winx64.exe winx64/cf${VERSION_MAJOR}.exe pushd win32 prepare_win_artifacts # -y flag avoids the default behavior of derefencing the link, so we archive the symlink as-is - zip -y cf8-cli_${INSTALLER_RELEASE_VERSION}_win32.zip * + zip -y cf${VERSION_MAJOR}-cli_${INSTALLER_RELEASE_VERSION}_win32.zip * popd pushd winx64 prepare_win_artifacts # -y flag avoids the default behavior of derefencing the link, so we archive the symlink as-is - zip -y cf8-cli_${INSTALLER_RELEASE_VERSION}_winx64.zip * + zip -y cf${VERSION_MAJOR}-cli_${INSTALLER_RELEASE_VERSION}_winx64.zip * popd popd - env: - INSTALLER_RELEASE_VERSION: ${{ env.INSTALLER_RELEASE_VERSION }} - name: Rearrange artifacts before upload run: | mkdir upload - cp -t upload \ + cp -v -t upload \ signed/cf-cli-linux-rpm-packages/cf*rpm \ signed/cf-cli-linux-deb-packages/cf*deb \ signed/cf-cli-macos-packages/cf*pkg \ @@ -809,51 +868,73 @@ jobs: signed/linux_i686/*tgz \ signed/linux_x86-64/*tgz \ signed/osx/*tgz \ + signed/macosarm/*tgz \ signed/win32/*zip \ signed/winx64/*zip - name: Upload installers to CLAW S3 bucket - if: ${{ github.ref_type == 'tag' }} # forked for security considerations uses: pivotalsoftware/s3-sync-action@v0.5.2 #pinned to no-default-region change env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_REGION: ${{ secrets.AWS_REGION }} + AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} - SOURCE_DIR: upload - DEST_DIR: "releases/v${{ env.INSTALLER_RELEASE_VERSION }}" + DEST_DIR: "releases/v${{ env.INSTALLER_RELEASE_VERSION }}" + SOURCE_DIR: upload - name: list S3 for human verification uses: docker://amazon/aws-cli:latest with: args: s3 ls "${{ env.AWS_S3_BUCKET }}/releases/v${{ env.INSTALLER_RELEASE_VERSION }}/" env: - AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_REGION: ${{ secrets.AWS_REGION }} + AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} INSTALLER_RELEASE_VERSION: ${{ env.INSTALLER_RELEASE_VERSION }} + # - name: SETUP UPTERM SESSION + # if: always() + # uses: lhotari/action-upterm@v1 + # timeout-minutes: 60 + # env: + # AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + # AWS_REGION: ${{ secrets.AWS_REGION }} + # AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + # AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + # GIT_RELEASE_TARGET_REPO: ${{ secrets.GIT_RELEASE_TARGET_REPO }} + # GIT_REPO_ACCESS_TOKEN: ${{ secrets.GIT_REPO_ACCESS_TOKEN }} + # SIGNING_KEY_GPG: ${{ secrets.SIGNING_KEY_GPG }} + # SIGNING_KEY_GPG_ID: ${{ secrets.SIGNING_KEY_GPG_ID }} + # SIGNING_KEY_GPG_PASSPHRASE: ${{ secrets.SIGNING_KEY_GPG_PASSPHRASE }} + # SIGNING_KEY_MAC_ID: ${{ secrets.SIGNING_KEY_MAC_ID }} + # SIGNING_KEY_MAC_PASSPHRASE: ${{ secrets.SIGNING_KEY_MAC_PASSPHRASE }} + # SIGNING_KEY_MAC_PFX: ${{ secrets.SIGNING_KEY_MAC_PFX }} + # SIGNING_KEY_WINDOWS_ID: ${{ secrets.SIGNING_KEY_WINDOWS_ID }} + # SIGNING_KEY_WINDOWS_PASSPHRASE: ${{ secrets.SIGNING_KEY_WINDOWS_PASSPHRASE }} + # SIGNING_KEY_WINDOWS_PFX: ${{ secrets.SIGNING_KEY_WINDOWS_PFX }} + # SIGNING_TEST_CA_MAC: ${{ secrets.SIGNING_TEST_CA_MAC }} + - name: Instruct human to update CLAW run: | echo "Please go to https://github.com/cloudfoundry/CLAW/blob/develop/claw-variables.yml and add the following line to the file:" echo echo "- ${INSTALLER_RELEASE_VERSION}" - - github-release-draft: name: Create GitHub Release Draft - if: ${{ github.ref_type == 'tag' }} runs-on: ubuntu-latest - environment: PROD permissions: actions: read contents: write needs: - - test-rpm-package - - test-deb-package - - test-macos - - test-windows + - setup + - test-rpm-package + - test-deb-package + - test-macos + - test-windows + environment: ${{ needs.setup.outputs.secrets-environment }} steps: - name: Download signed artifacts uses: actions/download-artifact@v2 @@ -863,9 +944,11 @@ jobs: - name: Create draft release uses: pivotalsoftware/action-gh-release@v1 with: - draft: true - repository: ${{ secrets.GIT_RELEASE_TARGET_REPO }} # repo to draft a release under, in / format - token: ${{ secrets.GIT_REPO_ACCESS_TOKEN }} # only needed when pushing to a repo other than 'self' + draft: true + name: "DRAFT v${{ env.INSTALLER_RELEASE_VERSION }}" + # tag_name: "v${{ env.INSTALLER_RELEASE_VERSION }}" + repository: ${{ secrets.GIT_RELEASE_TARGET_REPO }} # repo to draft a release under, in / format + token: ${{ secrets.GIT_REPO_ACCESS_TOKEN }} # only needed when pushing to a repo other than 'self' fail_on_unmatched_files: true files: | signed/cf-cli-linux-binaries/cf-cli* @@ -876,5 +959,109 @@ jobs: signed/cf-cli-windows-binaries/cf-cli*.exe signed/cf-cli-windows-packages/*.zip + test-rpm-package: + name: Test RPM Artifacts + needs: + - setup + - build-linux + environment: ${{ needs.setup.outputs.secrets-environment }} + runs-on: ubuntu-latest + container: + image: fedora + steps: + + - name: Download Signed Linux Packages + uses: actions/download-artifact@v2 + with: + name: cf-cli-linux-rpm-packages + + - name: Display structure of downloaded files + run: ls -R + + - name: Test RPMs + run: | + rpm -q --qf 'FN:\t%{FILENAMES}\nNAME:\t%{NAME}\nPGP:\t%{SIGPGP:pgpsig}\nGPG:\t%{SIGGPG:pgpsig}\n' -p *.rpm + + test-deb-package: + name: Test Debian Artifacts + needs: + - setup + - build-linux + environment: ${{ needs.setup.outputs.secrets-environment }} + runs-on: ubuntu-latest + container: + image: ubuntu + steps: + + - name: Download Signed Linux Packages + uses: actions/download-artifact@v2 + with: + name: cf-cli-linux-deb-packages + + - name: Display structure of downloaded files + run: | + ls -R + ls *.deb | xargs -n1 dpkg --info + + test-macos: + name: Test macOS Artifacts + needs: + - setup + - build-macos + environment: ${{ needs.setup.outputs.secrets-environment }} + runs-on: macos-latest + steps: + + - name: Download Signed macOS Packages + uses: actions/download-artifact@v2 + with: + name: cf-cli-macos-packages + + - name: Inspect macOS packages + run: | + ls -R + #TODO: DEV shim + pkgutil --check-signature * + + test-windows: + name: Test Windows Artifacts + needs: + - setup + - build-windows + environment: ${{ needs.setup.outputs.secrets-environment }} + runs-on: windows-latest + defaults: + run: + shell: pwsh + env: + VERSION_MAJOR: ${{ needs.setup.outputs.version-major }} + steps: + + - name: Download Signed Windows Binaries + uses: actions/download-artifact@v2 + with: + name: cf-cli-windows-binaries + + - name: Inspect Windows packages + run: | + Get-AuthenticodeSignature -Verbose -ErrorAction Stop .\cf-cli_win32.exe + Get-AuthenticodeSignature -Verbose -ErrorAction Stop .\cf-cli_winx64.exe + + - name: Download Signed Windows Binaries + uses: actions/download-artifact@v2 + with: + name: cf-cli-windows-packages + + - name: Inspect Windows files + run: | + Get-ChildItem -Force + + - name: View installer signature + run: | + Expand-Archive -DestinationPath winx64 -Path cf${env:VERSION_MAJOR}-cli-installer_*_winx64.zip + Expand-Archive -DestinationPath win32 -Path cf${env:VERSION_MAJOR}-cli-installer_*_win32.zip + + Get-AuthenticodeSignature -Verbose -ErrorAction Stop ".\winx64\cf${env:VERSION_MAJOR}_installer.exe" + Get-AuthenticodeSignature -Verbose -ErrorAction Stop ".\win32\cf${env:VERSION_MAJOR}_installer.exe" # vim: set sw=2 ts=2 sts=2 et tw=78 foldlevel=2 fdm=indent nospell: diff --git a/.github/workflows/update-repos.yml b/.github/workflows/update-repos.yml index c12e52459a3..16a39564cc1 100644 --- a/.github/workflows/update-repos.yml +++ b/.github/workflows/update-repos.yml @@ -1,12 +1,14 @@ name: Update Repositories on: + push: + branches: "v*" + workflow_dispatch: inputs: build_version: - description: 'Build Version' + description: 'build version format: n.n.n' required: true - default: '8.3.0' type: string permissions: @@ -17,35 +19,65 @@ defaults: shell: bash jobs: - shared-values: + setup: name: Setup runs-on: ubuntu-latest if: ${{ github.action_repository != 'cloudfoundry/cli' }} outputs: - build-version: ${{ steps.set-build-version.outputs.build-version }} secrets-environment: ${{ steps.set-secrets-environment.outputs.secrets-environment }} - steps: + version-build: ${{ steps.parse-semver.outputs.version-build }} + version-major: ${{ steps.parse-semver.outputs.version-major }} + version-minor: ${{ steps.parse-semver.outputs.version-minor }} + version-patch: ${{ steps.parse-semver.outputs.version-patch }} + claw-url: ${{ steps.set-claw-url.outputs.claw-url }} + + steps: - name: Set environment id: set-secrets-environment run: echo "::set-output name=secrets-environment::PROD" + - name: Set CLAW URL + id: set-claw-url + run: echo "::set-output name=claw-url::https://packages.cloudfoundry.org" + - name: Checkout cli uses: actions/checkout@v2 - - name: Set build version - id: set-build-version + - name: Parse semver + id: parse-semver run: | - version=$(cat BUILD_VERSION) - echo "::set-output name=build-version::$version" + VERSION=$(cat BUILD_VERSION) + VERSION="${VERSION#[vV]}" + + VERSION_MINOR="${VERSION#*.}" + VERSION_MINOR="${VERSION_MINOR%.*}" + + echo "::set-output name=version-build::${VERSION}" + echo "::set-output name=version-major::${VERSION%%\.*}" + echo "::set-output name=version-minor::${VERSION_MINOR}" + echo "::set-output name=version-patch::${VERSION##*.}" + + echo "VERSION_BUILD=${VERSION}" >> ${GITHUB_ENV} + + - name: Test if CLAW serve this version + env: + CLAW_URL: ${{ steps.set-claw-url.outputs.claw-url }} + run: > + set -vx + + curl --head "${CLAW_URL}/stable?release=linux64-binary&version=${VERSION_BUILD}&source=test" 2>&1 | + grep --quiet --regexp 'HTTP.*302' update-homebrew: name: Update Homebrew Repository runs-on: ubuntu-latest - needs: shared-values - environment: ${{ needs.shared-values.outputs.secrets-environment }} + needs: setup + environment: ${{ needs.setup.outputs.secrets-environment }} env: - BUILD_VERSION: ${{ needs.shared-values.outputs.build-version }} + CLAW_URL: ${{ needs.setup.outputs.claw-url }} + VERSION_BUILD: ${{ needs.setup.outputs.version-build }} + VERSION_MAJOR: ${{ needs.setup.outputs.version-major }} steps: - name: Checkout cli-ci @@ -64,70 +96,82 @@ jobs: ssh-key: ${{ secrets.GIT_DEPLOY_HOMEBREW_TAP }} - name: Setup - run: | - mkdir cf8-cli-osx-tarball cf8-cli-linux-tarball + run: > + mkdir + cf-cli-osx-tarball + cf-cli-macosarm-tarball + cf-cli-linux-tarball - name: Calculate checksums run: | set -x - curl -L "https://packages.cloudfoundry.org/stable?release=macosx64-binary&version=${BUILD_VERSION}&source=github-rel" \ - > cf8-cli-osx-tarball/cf8-cli_${BUILD_VERSION}_osx.tgz + curl -L "${CLAW_URL}/stable?release=macosx64-binary&version=${VERSION_BUILD}&source=github-rel" \ + > cf-cli-osx-tarball/cf-cli_osx.tgz - # Because CLAW always returns 200 we have to check if we got archive - file cf8-cli-osx-tarball/cf8-cli_${BUILD_VERSION}_osx.tgz | grep -q gzip || exit 1 + curl -L "${CLAW_URL}/stable?release=macosarm-binary&version=${VERSION_BUILD}&source=github-rel" \ + > cf-cli-macosarm-tarball/cf-cli_macosarm.tgz - curl -L "https://packages.cloudfoundry.org/stable?release=linux64-binary&version=${BUILD_VERSION}&source=github-rel" \ - > cf8-cli-linux-tarball/cf8-cli_${BUILD_VERSION}_linux64.tgz + curl -L "${CLAW_URL}/stable?release=linux64-binary&version=${VERSION_BUILD}&source=github-rel" \ + > cf-cli-linux-tarball/cf-cli_linux64.tgz # Because CLAW always returns 200 we have to check if we got archive - file cf8-cli-linux-tarball/cf8-cli_${BUILD_VERSION}_linux64.tgz | grep -q gzip || exit 1 + file cf-cli-osx-tarball/cf-cli_osx.tgz | grep -q gzip || exit 1 + file cf-cli-macosarm-tarball/cf-cli_macosarm.tgz | grep -q gzip || exit 1 + file cf-cli-linux-tarball/cf-cli_linux64.tgz | grep -q gzip || exit 1 - pushd cf8-cli-osx-tarball - CLI_OSX_SHA256=$(shasum -a 256 cf8-cli_*_osx.tgz | cut -d ' ' -f 1) + pushd cf-cli-osx-tarball + CLI_OSX_SHA256=$(shasum -a 256 cf-cli_osx.tgz | cut -d ' ' -f 1) popd - pushd cf8-cli-linux-tarball - CLI_LINUX_64_SHA256=$(shasum -a 256 cf8-cli_*_linux64.tgz | cut -d ' ' -f 1) + pushd cf-cli-macosarm-tarball + CLI_MACOSARM_SHA256=$(shasum -a 256 cf-cli_macosarm.tgz | cut -d ' ' -f 1) popd - echo "CLI_OSX_SHA256=${CLI_OSX_SHA256}" >> $GITHUB_ENV - echo "CLI_LINUX_64_SHA256=${CLI_LINUX_64_SHA256}" >> $GITHUB_ENV + pushd cf-cli-linux-tarball + CLI_LINUX_64_SHA256=$(shasum -a 256 cf-cli_linux64.tgz | cut -d ' ' -f 1) + popd + + echo "CLI_OSX_SHA256=${CLI_OSX_SHA256}" >> ${GITHUB_ENV} + echo "CLI_MACOSARM_SHA256=${CLI_MACOSARM_SHA256}" >> ${GITHUB_ENV} + echo "CLI_LINUX_64_SHA256=${CLI_LINUX_64_SHA256}" >> ${GITHUB_ENV} - name: Generate Homebrew formula file run: | set -ex pushd homebrew-tap - cat < cf-cli@8.rb - require 'formula' - - class CfCliAT8 < Formula - homepage 'https://code.cloudfoundry.org/cli' - version '${BUILD_VERSION}' + cat < cf-cli@${VERSION_MAJOR}.rb + class CfCliAT${VERSION_MAJOR} < Formula + desc "Cloud Foundry CLI" + homepage "https://code.cloudfoundry.org/cli" + version "${VERSION_BUILD}" if OS.mac? - url 'https://packages.cloudfoundry.org/homebrew/cf8-${BUILD_VERSION}.tgz' - sha256 '${CLI_OSX_SHA256}' + if Hardware::CPU.arm? + url "${CLAW_URL}/homebrew?arch=macosarm&version=${VERSION_BUILD}" + sha256 "${CLI_MACOSARM_SHA256}" + elsif + url "${CLAW_URL}/homebrew?arch=macosx64&version=${VERSION_BUILD}" + sha256 "${CLI_OSX_SHA256}" + end elsif OS.linux? - url 'https://packages.cloudfoundry.org/stable?release=linux64-binary&version=${BUILD_VERSION}&source=homebrew' - sha256 '${CLI_LINUX_64_SHA256}' + url "${CLAW_URL}/stable?release=linux64-binary&version=${VERSION_BUILD}&source=homebrew" + sha256 "${CLI_LINUX_64_SHA256}" end - depends_on :arch => :x86_64 - def install - bin.install 'cf8' - bin.install_symlink 'cf8' => 'cf' - (bash_completion/"cf8-cli").write <<-completion - $(cat ../cli-ci/ci/installers/completion/cf8) + bin.install "cf${VERSION_MAJOR}" + bin.install_symlink "cf${VERSION_MAJOR}" => "cf" + (bash_completion/"cf${VERSION_MAJOR}-cli").write <<-completion + $(cat ../cli-ci/ci/installers/completion/cf${VERSION_MAJOR}) completion - doc.install 'LICENSE' - doc.install 'NOTICE' + doc.install "LICENSE" + doc.install "NOTICE" end test do - system "#{bin}/cf8" + system "#{bin}/cf${VERSION_MAJOR}" end end EOF @@ -137,20 +181,20 @@ jobs: - name: Commit new homebrew formula run: | pushd homebrew-tap - git add cf-cli@8.rb + git add cf-cli@${VERSION_MAJOR}.rb if ! [ -z "$(git status --porcelain)"]; then git config user.name github-actions git config user.email github-actions@github.com - git commit -m "Release CF CLI $BUILD_VERSION" + git commit -m "Release CF CLI ${VERSION_BUILD}" else echo "no new version to commit" fi git push - echo "::group::cf-cli@8.rb" - cat cf-cli@8.rb + echo "::group::cf-cli@${VERSION_MAJOR}.rb" + cat cf-cli@${VERSION_MAJOR}.rb echo "::endgroup::" echo "::group::git show" @@ -163,47 +207,51 @@ jobs: name: Test Homebrew Repository runs-on: macos-latest needs: - - shared-values + - setup - update-homebrew - environment: ${{ needs.shared-values.outputs.secrets-environment }} + environment: ${{ needs.setup.outputs.secrets-environment }} env: - BUILD_VERSION: ${{ needs.shared-values.outputs.build-version }} + CLAW_URL: ${{ needs.setup.outputs.claw-url }} + VERSION_BUILD: ${{ needs.setup.outputs.version-build }} + VERSION_MAJOR: ${{ needs.setup.outputs.version-major }} steps: - name: Install CF CLI via Homebrew run: | set -evx - brew install cloudfoundry/tap/cf-cli@8 - installed_cf_version=$(cf8 version) + brew install cloudfoundry/tap/cf-cli@${VERSION_MAJOR} + installed_cf_version=$(cf${VERSION_MAJOR} version) cf_location=$(which cf) echo $cf_location echo $installed_cf_version - echo $BUILD_VERSION + echo ${VERSION_BUILD} codesign --verify $cf_location || echo --- - cf -v | grep "$BUILD_VERSION" + cf -v | grep "${VERSION_BUILD}" update-deb: name: Update Debian Repository runs-on: ubuntu-latest - needs: shared-values - environment: ${{ needs.shared-values.outputs.secrets-environment }} + needs: setup + environment: ${{ needs.setup.outputs.secrets-environment }} env: - BUILD_VERSION: ${{ needs.shared-values.outputs.build-version }} - AWS_BUCKET_NAME: cf-cli-debian-repo - AWS_DEFAULT_REGION: us-west-2 - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_BUCKET_NAME: cf-cli-debian-repo + AWS_DEFAULT_REGION: us-west-2 AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + CLAW_URL: ${{ needs.setup.outputs.claw-url }} + VERSION_BUILD: ${{ needs.setup.outputs.version-build }} + VERSION_MAJOR: ${{ needs.setup.outputs.version-major }} steps: - name: Setup run: | - echo "BUILD_VERSION: $BUILD_VERSION" - echo "Environment: $ENVIRONMENT" + echo "VERSION_BUILD: ${VERSION_BUILD}" + echo "Environment: ${ENVIRONMENT}" - name: Checkout uses: actions/checkout@v2 @@ -217,10 +265,10 @@ jobs: - name: Load GPG key env: - SIGNING_KEY_GPG: ${{ secrets.SIGNING_KEY_GPG }} + SIGNING_KEY_GPG: ${{ secrets.SIGNING_KEY_GPG }} SIGNING_KEY_GPG_PASSPHRASE: ${{ secrets.SIGNING_KEY_GPG_PASSPHRASE }} run: | - echo -n "$SIGNING_KEY_GPG" | base64 --decode | gpg --no-tty --batch --pinentry-mode loopback --import + echo -n "${SIGNING_KEY_GPG}" | base64 --decode | gpg --no-tty --batch --pinentry-mode loopback --import - name: View GPG keys run: gpg --list-keys @@ -230,10 +278,10 @@ jobs: echo "Configure GPG" # mkdir gpg-dir - # export GNUPGHOME=$PWD/gpg-dir - # chmod 700 $GNUPGHOME + # export GNUPGHOME=${PWD}/gpg-dir + # chmod 700 ${GNUPGHOME} # TODO: restore - # trap "rm -rf $GNUPGHOME" 0 + # trap "rm -rf ${GNUPGHOME}" 0 cat >> ~/gpg.conf < installers/cf8-cli-installer_${BUILD_VERSION}_i686.deb - curl -L "https://cli.run.pivotal.io/stable?release=debian64&version=${BUILD_VERSION}&source=github-rel" > installers/cf8-cli-installer_${BUILD_VERSION}_x86-64.deb + curl -L "${CLAW_URL}/stable?release=debian32&version=${VERSION_BUILD}&source=github-rel" > installers/cf${VERSION_MAJOR}-cli-installer_${VERSION_BUILD}_i686.deb + curl -L "${CLAW_URL}/stable?release=debian64&version=${VERSION_BUILD}&source=github-rel" > installers/cf${VERSION_MAJOR}-cli-installer_${VERSION_BUILD}_x86-64.deb - name: Update Debian Repository env: - DEBIAN_FRONTEND: noninteractive + DEBIAN_FRONTEND: noninteractive SIGNING_KEY_GPG_ID: ${{ secrets.SIGNING_KEY_GPG_ID }} run: | deb-s3 upload installers/*.deb \ @@ -261,11 +309,13 @@ jobs: name: Test Debian Repository runs-on: ubuntu-latest needs: - - shared-values + - setup - update-deb - environment: ${{ needs.shared-values.outputs.secrets-environment }} + environment: ${{ needs.setup.outputs.secrets-environment }} env: - BUILD_VERSION: ${{ needs.shared-values.outputs.build-version }} + CLAW_URL: ${{ needs.setup.outputs.claw-url }} + VERSION_BUILD: ${{ needs.setup.outputs.version-build }} + VERSION_MAJOR: ${{ needs.setup.outputs.version-major }} steps: - name: Install CF CLI via apt @@ -275,45 +325,48 @@ jobs: sudo apt update sudo apt install -y wget gnupg - wget -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo apt-key add - - echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list + wget -q -O - ${CLAW_URL}/debian/cli.cloudfoundry.org.key | sudo apt-key add - + echo "deb ${CLAW_URL}/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list sudo apt update - sudo apt install -y cf8-cli + sudo apt install -y cf${VERSION_MAJOR}-cli which cf set -x cf -v - cf8 -v + cf${VERSION_MAJOR} -v - cf -v | grep "$BUILD_VERSION" + cf -v | grep "${VERSION_BUILD}" update-rpm: name: Update RPM Repository runs-on: ubuntu-18.04 - environment: ${{ needs.shared-values.outputs.secrets-environment }} - needs: shared-values + environment: ${{ needs.setup.outputs.secrets-environment }} + needs: setup env: - AWS_DEFAULT_REGION: us-east-1 - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_DEFAULT_REGION: us-east-1 AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + CLAW_URL: ${{ needs.setup.outputs.claw-url }} + VERSION_BUILD: ${{ needs.setup.outputs.version-build }} + VERSION_MAJOR: ${{ needs.setup.outputs.version-major }} steps: - name: Setup env: - BUILD_VERSION: ${{ github.event.inputs.build_version }} - ENVIRONMENT: ${{ github.event.inputs.environment }} + ENVIRONMENT: ${{ github.event.inputs.environment }} + VERSION_BUILD: ${{ github.event.inputs.build_version }} run: | - echo "BUILD_VERSION: $BUILD_VERSION" - echo "Environment: $ENVIRONMENT" + echo "VERSION_BUILD: ${VERSION_BUILD}" + echo "Environment: ${ENVIRONMENT}" # TODO: fix backup # - name: Download current RPM repodata # env: - # AWS_DEFAULT_REGION: us-east-1 - # AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + # AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + # AWS_DEFAULT_REGION: us-east-1 # AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # uses: docker://amazon/aws-cli:latest # with: @@ -387,30 +440,32 @@ jobs: test-rpm-repo: name: Test RPM Repository needs: - - shared-values + - setup - update-rpm runs-on: ubuntu-latest container: image: fedora - environment: ${{ needs.shared-values.outputs.secrets-environment }} + environment: ${{ needs.setup.outputs.secrets-environment }} env: - BUILD_VERSION: ${{ needs.shared-values.outputs.build-version }} + CLAW_URL: ${{ needs.setup.outputs.claw-url }} + VERSION_BUILD: ${{ needs.setup.outputs.version-build }} + VERSION_MAJOR: ${{ needs.setup.outputs.version-major }} steps: - name: Configure Custom CF Repository run: | curl -sL -o /etc/yum.repos.d/cloudfoundry-cli.repo \ - https://packages.cloudfoundry.org/fedora/cloudfoundry-cli.repo + ${CLAW_URL}/fedora/cloudfoundry-cli.repo - - name: Install cf8-cli package - run: dnf install -y cf8-cli + - name: Install cf cli package + run: dnf install -y cf${VERSION_MAJOR}-cli - name: Print CF CLI Versions run: | cf -v - cf8 -v + cf${VERSION_MAJOR} -v - name: Test Version Match - run: cf -v | grep -q "$BUILD_VERSION" + run: cf -v | grep -q "${VERSION_BUILD}" # vim: set sw=2 ts=2 sts=2 et tw=78 foldlevel=2 fdm=indent nospell: diff --git a/Makefile b/Makefile index aa70bbe8001..11195a1cb8c 100644 --- a/Makefile +++ b/Makefile @@ -175,9 +175,9 @@ out/cf-cli_osx: $(GOSRC) GOARCH=amd64 GOOS=darwin go build \ -a -ldflags "$(LD_FLAGS)" -o out/cf-cli_osx . -out/cf-cli_osx_arm: $(GOSRC) +out/cf-cli_macosarm: $(GOSRC) GOARCH=arm64 GOOS=darwin go build \ - -a -ldflags "$(LD_FLAGS)" -o out/cf-cli_osx_arm . + -a -ldflags "$(LD_FLAGS)" -o out/cf-cli_macosarm . out/cf-cli_win32.exe: $(GOSRC) rsrc.syso GOARCH=386 GOOS=windows go build -tags="forceposix" -o out/cf-cli_win32.exe -ldflags "$(LD_FLAGS)" . diff --git a/bin/generate-release-notes b/bin/generate-release-notes index 0d7d8649681..1246d0af5cc 100755 --- a/bin/generate-release-notes +++ b/bin/generate-release-notes @@ -9,22 +9,22 @@ Package Manager Installation Installers ---------- -- Debian [64 bit](https://packages.cloudfoundry.org/stable?release=debian64&version=$VERSION&source=github-rel) / [32 bit](https://packages.cloudfoundry.org/stable?release=debian32&version=$VERSION&source=github-rel) (deb) -- Redhat [64 bit](https://packages.cloudfoundry.org/stable?release=redhat64&version=$VERSION&source=github-rel) / [32 bit](https://packages.cloudfoundry.org/stable?release=redhat32&version=$VERSION&source=github-rel) (rpm) -- Mac OS X [64 bit](https://packages.cloudfoundry.org/stable?release=macosx64&version=$VERSION&source=github-rel) (pkg) -- Windows [64 bit](https://packages.cloudfoundry.org/stable?release=windows64&version=$VERSION&source=github-rel) / [32 bit](https://packages.cloudfoundry.org/stable?release=windows32&version=$VERSION&source=github-rel) (zip) +- Debian [64 bit](https://packages.cloudfoundry.org/stable?release=debian64&version=${VERSION}&source=github-rel) / [32 bit](https://packages.cloudfoundry.org/stable?release=debian32&version=${VERSION}&source=github-rel) (deb) +- Redhat [64 bit](https://packages.cloudfoundry.org/stable?release=redhat64&version=${VERSION}&source=github-rel) / [32 bit](https://packages.cloudfoundry.org/stable?release=redhat32&version=${VERSION}&source=github-rel) (rpm) +- macOS [64 bit](https://packages.cloudfoundry.org/stable?release=macosx64&version=${VERSION}&source=github-rel) / [arm](https://packages.cloudfoundry.org/stable?release=macosarm&version=${VERSION}&source=github-rel) (pkg) +- Windows [64 bit](https://packages.cloudfoundry.org/stable?release=windows64&version=${VERSION}&source=github-rel) / [32 bit](https://packages.cloudfoundry.org/stable?release=windows32&version=${VERSION}&source=github-rel) (zip) Binaries -------- -- Linux [64 bit](https://packages.cloudfoundry.org/stable?release=linux64-binary&version=$VERSION&source=github-rel) / [32 bit](https://packages.cloudfoundry.org/stable?release=linux32-binary&version=$VERSION&source=github-rel) (tgz) -- Mac OS X [64 bit](https://packages.cloudfoundry.org/stable?release=macosx64-binary&version=$VERSION&source=github-rel) (tgz) -- Windows [64 bit](https://packages.cloudfoundry.org/stable?release=windows64-exe&version=$VERSION&source=github-rel) / [32 bit](https://packages.cloudfoundry.org/stable?release=windows32-exe&version=$VERSION&source=github-rel) (zip) +- Linux [64 bit](https://packages.cloudfoundry.org/stable?release=linux64-binary&version=${VERSION}&source=github-rel) / [32 bit](https://packages.cloudfoundry.org/stable?release=linux32-binary&version=${VERSION}&source=github-rel) (tgz) +- macOS [64 bit](https://packages.cloudfoundry.org/stable?release=macosx64-binary&version=${VERSION}&source=github-rel) / [arm](https://packages.cloudfoundry.org/stable?release=macosarm-binary&version=${VERSION}&source=github-rel) (tgz) +- Windows [64 bit](https://packages.cloudfoundry.org/stable?release=windows64-exe&version=${VERSION}&source=github-rel) / [32 bit](https://packages.cloudfoundry.org/stable?release=windows32-exe&version=${VERSION}&source=github-rel) (zip) Docker -------- \`\`\`shell -docker pull cloudfoundry/cli:$VERSION +docker pull cloudfoundry/cli:${VERSION} \`\`\` Change Log From 14792b6578dab44937d7af97bdf410e8e0a7d4ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristhian=20Pe=C3=B1a?= Date: Mon, 6 Jun 2022 17:17:31 -0500 Subject: [PATCH 033/248] Bump Sinatra version for fixtures example-app from 2.0.4 to 2.2.0 Co-authored by: George Gelashvili --- fixtures/applications/example-app/Gemfile | 2 +- fixtures/applications/example-app/Gemfile.lock | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/fixtures/applications/example-app/Gemfile b/fixtures/applications/example-app/Gemfile index 81d2efc1d69..f4ebacb273c 100644 --- a/fixtures/applications/example-app/Gemfile +++ b/fixtures/applications/example-app/Gemfile @@ -2,4 +2,4 @@ source "https://rubygems.org" ruby "2.5.1" -gem "sinatra" +gem "sinatra", "~> 2.2.0" diff --git a/fixtures/applications/example-app/Gemfile.lock b/fixtures/applications/example-app/Gemfile.lock index 6c625c63d55..06d05ea6221 100644 --- a/fixtures/applications/example-app/Gemfile.lock +++ b/fixtures/applications/example-app/Gemfile.lock @@ -1,22 +1,24 @@ GEM remote: https://rubygems.org/ specs: - mustermann (1.0.3) - rack (2.2.3) - rack-protection (2.0.4) + mustermann (1.1.1) + ruby2_keywords (~> 0.0.1) + rack (2.2.3.1) + rack-protection (2.2.0) rack - sinatra (2.0.4) + ruby2_keywords (0.0.5) + sinatra (2.2.0) mustermann (~> 1.0) - rack (~> 2.0) - rack-protection (= 2.0.4) + rack (~> 2.2) + rack-protection (= 2.2.0) tilt (~> 2.0) - tilt (2.0.9) + tilt (2.0.10) PLATFORMS ruby DEPENDENCIES - sinatra + sinatra (~> 2.2.0) RUBY VERSION ruby 2.5.1p57 From dd9a0c0fce1c3deef544854dfd317137f874752e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristhian=20Pe=C3=B1a?= Date: Tue, 7 Jun 2022 16:44:53 -0500 Subject: [PATCH 034/248] Revert "Bump Sinatra version for fixtures example-app from 2.0.4 to 2.2.0" This reverts commit 14792b6578dab44937d7af97bdf410e8e0a7d4ce. We will follow the PR flow as always. --- fixtures/applications/example-app/Gemfile | 2 +- fixtures/applications/example-app/Gemfile.lock | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/fixtures/applications/example-app/Gemfile b/fixtures/applications/example-app/Gemfile index f4ebacb273c..81d2efc1d69 100644 --- a/fixtures/applications/example-app/Gemfile +++ b/fixtures/applications/example-app/Gemfile @@ -2,4 +2,4 @@ source "https://rubygems.org" ruby "2.5.1" -gem "sinatra", "~> 2.2.0" +gem "sinatra" diff --git a/fixtures/applications/example-app/Gemfile.lock b/fixtures/applications/example-app/Gemfile.lock index 06d05ea6221..6c625c63d55 100644 --- a/fixtures/applications/example-app/Gemfile.lock +++ b/fixtures/applications/example-app/Gemfile.lock @@ -1,24 +1,22 @@ GEM remote: https://rubygems.org/ specs: - mustermann (1.1.1) - ruby2_keywords (~> 0.0.1) - rack (2.2.3.1) - rack-protection (2.2.0) + mustermann (1.0.3) + rack (2.2.3) + rack-protection (2.0.4) rack - ruby2_keywords (0.0.5) - sinatra (2.2.0) + sinatra (2.0.4) mustermann (~> 1.0) - rack (~> 2.2) - rack-protection (= 2.2.0) + rack (~> 2.0) + rack-protection (= 2.0.4) tilt (~> 2.0) - tilt (2.0.10) + tilt (2.0.9) PLATFORMS ruby DEPENDENCIES - sinatra (~> 2.2.0) + sinatra RUBY VERSION ruby 2.5.1p57 From 5abaa243cea7cd732fcbf70e345569acf6ec6302 Mon Sep 17 00:00:00 2001 From: Shwetha Gururaj Date: Wed, 15 Jun 2022 18:35:45 +0000 Subject: [PATCH 035/248] Skipping SSL validation tests for macOS Starting golang 1.18 system APIs are used for certificate verification on macOS instead of built-in go verifier. Which makes behavior similar to Windows. Since we are skipping this test for Windows due to difficulties with execution order we believe it's fair to skip it in macOS too and rely on Linux test. References: - [Changes to x509 in Go 1.18 conversation](https://groups.google.com/g/golang-nuts/c/RGghq2gTWss/m/7GsudTfCAgAJ) - https://cs.opensource.google/go/go/+/master:src/crypto/x509/root_darwin.go;l=52 - https://cs.opensource.google/go/go/+/master:src/crypto/x509/verify.go;l=766 Co-authored-by: Alexander Berezovsky --- .github/workflows/units.yml | 8 ++++---- api/cloudcontroller/cloud_controller_connection_test.go | 7 +++++-- api/plugin/plugin_connection_test.go | 7 +++++-- api/uaa/uaa_connection_test.go | 4 ++++ cf/net/gateway_test.go | 6 ++++++ cf/util/testhelpers/net/make_tls_cert.go | 2 +- 6 files changed, 25 insertions(+), 9 deletions(-) diff --git a/.github/workflows/units.yml b/.github/workflows/units.yml index 381e21aa522..2462a8b88b9 100644 --- a/.github/workflows/units.yml +++ b/.github/workflows/units.yml @@ -65,8 +65,8 @@ jobs: - name: Set up Test run: | - go get -u github.com/onsi/ginkgo/ginkgo - go get github.com/onsi/gomega/matchers@v1.10.5 + go install github.com/onsi/ginkgo/ginkgo@v1.16.4 + go install github.com/onsi/gomega/matchers - name: Run Linux Units run: make units @@ -98,8 +98,8 @@ jobs: - name: Set up Test run: | - go get -u github.com/onsi/ginkgo/ginkgo - go get github.com/onsi/gomega/matchers@v1.10.5 + go install github.com/onsi/ginkgo/ginkgo@v1.16.4 + go install github.com/onsi/gomega/matchers - name: Get build-time dependencies run: | diff --git a/api/cloudcontroller/cloud_controller_connection_test.go b/api/cloudcontroller/cloud_controller_connection_test.go index c0dbbd5c3d7..747d6ff71f9 100644 --- a/api/cloudcontroller/cloud_controller_connection_test.go +++ b/api/cloudcontroller/cloud_controller_connection_test.go @@ -253,6 +253,9 @@ var _ = Describe("Cloud Controller Connection", func() { When("the server does not have a verified certificate", func() { Context("skipSSLValidation is false", func() { BeforeEach(func() { + if runtime.GOOS == "darwin" { + Skip("ssl verification is different on darwin") + } server.AppendHandlers( CombineHandlers( VerifyRequest(http.MethodGet, "/v2/foo"), @@ -277,8 +280,8 @@ var _ = Describe("Cloud Controller Connection", func() { When("the server's certificate does not match the hostname", func() { Context("skipSSLValidation is false", func() { BeforeEach(func() { - if runtime.GOOS == "windows" { - Skip("ssl validation has a different order on windows, will not be returned properly") + if runtime.GOOS == "windows" || runtime.GOOS == "darwin" { + Skip("ssl validation has a different order on windows/darwin, will not be returned properly") } server.AppendHandlers( CombineHandlers( diff --git a/api/plugin/plugin_connection_test.go b/api/plugin/plugin_connection_test.go index 6415fdc7b9c..5e1a2fd12b6 100644 --- a/api/plugin/plugin_connection_test.go +++ b/api/plugin/plugin_connection_test.go @@ -155,6 +155,9 @@ var _ = Describe("Plugin Connection", func() { When("the server does not have a verified certificate", func() { Context("skipSSLValidation is false", func() { BeforeEach(func() { + if runtime.GOOS == "darwin" { + Skip("ssl verification is different on darwin") + } server.AppendHandlers( CombineHandlers( VerifyRequest(http.MethodGet, "/list"), @@ -178,8 +181,8 @@ var _ = Describe("Plugin Connection", func() { When("the server's certificate does not match the hostname", func() { Context("skipSSLValidation is false", func() { BeforeEach(func() { - if runtime.GOOS == "windows" { - Skip("ssl validation has a different order on windows, will not be returned properly") + if runtime.GOOS == "windows" || runtime.GOOS == "darwin" { + Skip("ssl validation has a different order on windows/darwin, will not be returned properly") } server.AppendHandlers( CombineHandlers( diff --git a/api/uaa/uaa_connection_test.go b/api/uaa/uaa_connection_test.go index ed49ccdac82..129c72cc178 100644 --- a/api/uaa/uaa_connection_test.go +++ b/api/uaa/uaa_connection_test.go @@ -3,6 +3,7 @@ package uaa_test import ( "fmt" "net/http" + "runtime" . "code.cloudfoundry.org/cli/api/uaa" . "github.com/onsi/ginkgo" @@ -120,6 +121,9 @@ var _ = Describe("UAA Connection", func() { When("the server does not have a verified certificate", func() { Context("skipSSLValidation is false", func() { BeforeEach(func() { + if runtime.GOOS == "darwin" { + Skip("ssl verification is different on darwin") + } server.AppendHandlers( CombineHandlers( VerifyRequest(http.MethodGet, "/v2/foo"), diff --git a/cf/net/gateway_test.go b/cf/net/gateway_test.go index bdc15877344..88c957ca0b2 100644 --- a/cf/net/gateway_test.go +++ b/cf/net/gateway_test.go @@ -528,7 +528,13 @@ var _ = Describe("Gateway", func() { }) Context("when SSL validation is enabled", func() { + BeforeEach(func() { + if runtime.GOOS == "darwin" { + Skip("ssl verification is different on darwin") + } + }) It("returns an invalid cert error if the server's CA is unknown (e.g. cert is self-signed)", func() { + apiServer.TLS.Certificates = []tls.Certificate{testnet.MakeSelfSignedTLSCert()} _, apiErr := ccGateway.PerformRequest(request) diff --git a/cf/util/testhelpers/net/make_tls_cert.go b/cf/util/testhelpers/net/make_tls_cert.go index ab55003fb0d..d681898d6e2 100644 --- a/cf/util/testhelpers/net/make_tls_cert.go +++ b/cf/util/testhelpers/net/make_tls_cert.go @@ -30,7 +30,7 @@ func MakeUnauthorizedTLSCert() tls.Certificate { } func generateCert(hosts []string, notAfter time.Time, isAuthorizedToSign bool) tls.Certificate { - priv, err := rsa.GenerateKey(rand.Reader, 1024) + priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { panic(err) } From 9bf740f0a9c35a733f87a344d6e15eb9434ab7f1 Mon Sep 17 00:00:00 2001 From: Shwetha Gururaj Date: Mon, 6 Jun 2022 18:53:15 +0000 Subject: [PATCH 036/248] Bump golang to 1.18 Co-authored-by: Alexander Berezovsky --- .github/workflows/build-sign-upload.yml | 2 +- .github/workflows/units.yml | 2 +- go.mod | 10 +++++----- go.sum | 21 ++++++++------------- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build-sign-upload.yml b/.github/workflows/build-sign-upload.yml index c914ad1a782..7b854937c6c 100644 --- a/.github/workflows/build-sign-upload.yml +++ b/.github/workflows/build-sign-upload.yml @@ -129,7 +129,7 @@ jobs: - name: Set go version id: set-go-version - run: echo "::set-output name=go-version::1.17" + run: echo "::set-output name=go-version::1.18" # This is for debugging. It's equivalent to fly intecept # - name: Setup upterm session diff --git a/.github/workflows/units.yml b/.github/workflows/units.yml index 2462a8b88b9..209cae73b3f 100644 --- a/.github/workflows/units.yml +++ b/.github/workflows/units.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@v2 - id: set-go-version run: | - echo "::set-output name=go-version::1.17" + echo "::set-output name=go-version::1.18" lint: name: Lint code diff --git a/go.mod b/go.mod index e1d57e6a039..5169eb5ea3c 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module code.cloudfoundry.org/cli -go 1.17 +go 1.18 require ( code.cloudfoundry.org/bytefmt v0.0.0-20170428003108-f4415fafc561 @@ -39,8 +39,8 @@ require ( github.com/sirupsen/logrus v1.2.0 github.com/tedsuo/rata v1.0.1-0.20170830210128-07d200713958 github.com/vito/go-interact v0.0.0-20171111012221-fa338ed9e9ec - golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 - golang.org/x/net v0.0.0-20211013171255-e13a2654a71e + golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e + golang.org/x/net v0.0.0-20220531201128-c960675eff93 golang.org/x/text v0.3.7 gopkg.in/cheggaaa/pb.v1 v1.0.28 gopkg.in/yaml.v2 v2.4.0 @@ -84,8 +84,8 @@ require ( github.com/tedsuo/ifrit v0.0.0-20191009134036-9a97d0632f00 // indirect golang.org/x/mod v0.4.2 // indirect golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect - golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect - golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect + golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect golang.org/x/tools v0.1.6-0.20210908190839-cf92b39a962c // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect diff --git a/go.sum b/go.sum index 46324f18f2e..dc1993b5db4 100644 --- a/go.sum +++ b/go.sum @@ -240,7 +240,6 @@ github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.6.0 h1:rgxjzoDmDXw5q8HONgyHhBas4to0/XWRo/gPpJhsUNQ= github.com/grpc-ecosystem/grpc-gateway/v2 v2.6.0/go.mod h1:qrJPVzv9YlhsrxJc3P/Q85nr0w1lIRikTl4JlhdDH5w= @@ -380,7 +379,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -396,8 +394,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 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-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -465,13 +463,11 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211013171255-e13a2654a71e h1:Xj+JO91noE97IN6F/7WZxzC5QE6yENAQPrwIYhW3bsA= -golang.org/x/net v0.0.0-20211013171255-e13a2654a71e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220531201128-c960675eff93 h1:MYimHLfoXEpOhqd/zgoA/uoXzHB86AEky4LAx5ij9xA= +golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -531,16 +527,15 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211013075003-97ac67df715c h1:taxlMj0D/1sOAuv/CbSD+MMDof2vbyPTqz5FNYKpXt8= -golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From 9ee314c30ceb41c336de05c35c4efad9d70509da Mon Sep 17 00:00:00 2001 From: Shwetha Gururaj Date: Mon, 6 Jun 2022 19:27:49 +0000 Subject: [PATCH 037/248] Parse pipelines go version from go.mod We want to use single source of truth go.mod, instead of configuration scattered across multiple places. Co-authored-by: Alexander Berezovsky --- .github/workflows/build-sign-upload.yml | 7 +++++-- .github/workflows/units.yml | 7 ++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-sign-upload.yml b/.github/workflows/build-sign-upload.yml index 7b854937c6c..d516281b37e 100644 --- a/.github/workflows/build-sign-upload.yml +++ b/.github/workflows/build-sign-upload.yml @@ -127,9 +127,12 @@ jobs: echo "::set-output name=version-minor::${VERSION_MINOR}" echo "::set-output name=version-patch::${VERSION##*.}" - - name: Set go version + - name: Parse Golang Version id: set-go-version - run: echo "::set-output name=go-version::1.18" + run: | + go_version=($(grep -E '^go 1\.[[:digit:]]{1,2}' go.mod)) + echo "golang version: ${go_version[1]}" + echo "::set-output name=go-version::${go_version[1]}" # This is for debugging. It's equivalent to fly intecept # - name: Setup upterm session diff --git a/.github/workflows/units.yml b/.github/workflows/units.yml index 209cae73b3f..db2f329155e 100644 --- a/.github/workflows/units.yml +++ b/.github/workflows/units.yml @@ -19,11 +19,16 @@ jobs: outputs: go-version: ${{ steps.set-go-version.outputs.go-version }} steps: + - name: Checkout uses: actions/checkout@v2 + - id: set-go-version + name: Parse Golang Version run: | - echo "::set-output name=go-version::1.18" + go_version=($(grep -E '^go 1\.[[:digit:]]{1,2}' go.mod)) + echo "golang version: ${go_version[1]}" + echo "::set-output name=go-version::${go_version[1]}" lint: name: Lint code From 3346dae7885f977f587911d908c4fbaaf2565b3f Mon Sep 17 00:00:00 2001 From: Juan Diego Gonzalez Date: Wed, 8 Jun 2022 20:37:51 +0000 Subject: [PATCH 038/248] Implements new command `share-route` This command is used for sharing a route in between two spaces in order to facilitate the movement of apps in between spaces. Co-authored-by: Juan Diego Gonzalez --- actor/v7action/cloud_controller_client.go | 1 + actor/v7action/route.go | 5 +- .../fake_cloud_controller_client.go | 80 +++++ .../ccv3/internal/api_routes.go | 2 + api/cloudcontroller/ccv3/route.go | 25 ++ command/common/command_list_v7.go | 1 + command/common/internal/help_all_display.go | 1 + command/v7/actor.go | 1 + command/v7/share_route_command.go | 101 +++++++ command/v7/share_route_command_test.go | 279 ++++++++++++++++++ command/v7/v7fakes/fake_actor.go | 80 +++++ .../v7/isolated/share_route_command_test.go | 204 +++++++++++++ 12 files changed, 779 insertions(+), 1 deletion(-) create mode 100644 command/v7/share_route_command.go create mode 100644 command/v7/share_route_command_test.go create mode 100644 integration/v7/isolated/share_route_command_test.go diff --git a/actor/v7action/cloud_controller_client.go b/actor/v7action/cloud_controller_client.go index 5bca12c73b0..756c0528ffd 100644 --- a/actor/v7action/cloud_controller_client.go +++ b/actor/v7action/cloud_controller_client.go @@ -149,6 +149,7 @@ type CloudControllerClient interface { SetApplicationDroplet(appGUID string, dropletGUID string) (resources.Relationship, ccv3.Warnings, error) SharePrivateDomainToOrgs(domainGuid string, sharedOrgs ccv3.SharedOrgs) (ccv3.Warnings, error) ShareServiceInstanceToSpaces(serviceInstanceGUID string, spaceGUIDs []string) (resources.RelationshipList, ccv3.Warnings, error) + ShareRoute(routeGUID string, spaceGUID string) (ccv3.Warnings, error) TargetCF(settings ccv3.TargetSettings) UnbindSecurityGroupRunningSpace(securityGroupGUID string, spaceGUID string) (ccv3.Warnings, error) UnbindSecurityGroupStagingSpace(securityGroupGUID string, spaceGUID string) (ccv3.Warnings, error) diff --git a/actor/v7action/route.go b/actor/v7action/route.go index e91d5434473..16f7bc9f4ce 100644 --- a/actor/v7action/route.go +++ b/actor/v7action/route.go @@ -406,7 +406,10 @@ func (actor Actor) UnmapRoute(routeGUID string, destinationGUID string) (Warning warnings, err := actor.CloudControllerClient.UnmapRoute(routeGUID, destinationGUID) return Warnings(warnings), err } - +func (actor Actor) ShareRoute(routeGUID string, spaceGUID string) (Warnings, error) { + warnings, err := actor.CloudControllerClient.ShareRoute(routeGUID, spaceGUID) + return Warnings(warnings), err +} func (actor Actor) GetApplicationRoutes(appGUID string) ([]resources.Route, Warnings, error) { allWarnings := Warnings{} diff --git a/actor/v7action/v7actionfakes/fake_cloud_controller_client.go b/actor/v7action/v7actionfakes/fake_cloud_controller_client.go index bc955a70bba..15a378271c2 100644 --- a/actor/v7action/v7actionfakes/fake_cloud_controller_client.go +++ b/actor/v7action/v7actionfakes/fake_cloud_controller_client.go @@ -2076,6 +2076,20 @@ type FakeCloudControllerClient struct { result1 ccv3.Warnings result2 error } + ShareRouteStub func(string, string) (ccv3.Warnings, error) + shareRouteMutex sync.RWMutex + shareRouteArgsForCall []struct { + arg1 string + arg2 string + } + shareRouteReturns struct { + result1 ccv3.Warnings + result2 error + } + shareRouteReturnsOnCall map[int]struct { + result1 ccv3.Warnings + result2 error + } ShareServiceInstanceToSpacesStub func(string, []string) (resources.RelationshipList, ccv3.Warnings, error) shareServiceInstanceToSpacesMutex sync.RWMutex shareServiceInstanceToSpacesArgsForCall []struct { @@ -11688,6 +11702,70 @@ func (fake *FakeCloudControllerClient) SharePrivateDomainToOrgsReturnsOnCall(i i }{result1, result2} } +func (fake *FakeCloudControllerClient) ShareRoute(arg1 string, arg2 string) (ccv3.Warnings, error) { + fake.shareRouteMutex.Lock() + ret, specificReturn := fake.shareRouteReturnsOnCall[len(fake.shareRouteArgsForCall)] + fake.shareRouteArgsForCall = append(fake.shareRouteArgsForCall, struct { + arg1 string + arg2 string + }{arg1, arg2}) + fake.recordInvocation("ShareRoute", []interface{}{arg1, arg2}) + fake.shareRouteMutex.Unlock() + if fake.ShareRouteStub != nil { + return fake.ShareRouteStub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.shareRouteReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeCloudControllerClient) ShareRouteCallCount() int { + fake.shareRouteMutex.RLock() + defer fake.shareRouteMutex.RUnlock() + return len(fake.shareRouteArgsForCall) +} + +func (fake *FakeCloudControllerClient) ShareRouteCalls(stub func(string, string) (ccv3.Warnings, error)) { + fake.shareRouteMutex.Lock() + defer fake.shareRouteMutex.Unlock() + fake.ShareRouteStub = stub +} + +func (fake *FakeCloudControllerClient) ShareRouteArgsForCall(i int) (string, string) { + fake.shareRouteMutex.RLock() + defer fake.shareRouteMutex.RUnlock() + argsForCall := fake.shareRouteArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeCloudControllerClient) ShareRouteReturns(result1 ccv3.Warnings, result2 error) { + fake.shareRouteMutex.Lock() + defer fake.shareRouteMutex.Unlock() + fake.ShareRouteStub = nil + fake.shareRouteReturns = struct { + result1 ccv3.Warnings + result2 error + }{result1, result2} +} + +func (fake *FakeCloudControllerClient) ShareRouteReturnsOnCall(i int, result1 ccv3.Warnings, result2 error) { + fake.shareRouteMutex.Lock() + defer fake.shareRouteMutex.Unlock() + fake.ShareRouteStub = nil + if fake.shareRouteReturnsOnCall == nil { + fake.shareRouteReturnsOnCall = make(map[int]struct { + result1 ccv3.Warnings + result2 error + }) + } + fake.shareRouteReturnsOnCall[i] = struct { + result1 ccv3.Warnings + result2 error + }{result1, result2} +} + func (fake *FakeCloudControllerClient) ShareServiceInstanceToSpaces(arg1 string, arg2 []string) (resources.RelationshipList, ccv3.Warnings, error) { var arg2Copy []string if arg2 != nil { @@ -14659,6 +14737,8 @@ func (fake *FakeCloudControllerClient) Invocations() map[string][][]interface{} defer fake.setApplicationDropletMutex.RUnlock() fake.sharePrivateDomainToOrgsMutex.RLock() defer fake.sharePrivateDomainToOrgsMutex.RUnlock() + fake.shareRouteMutex.RLock() + defer fake.shareRouteMutex.RUnlock() fake.shareServiceInstanceToSpacesMutex.RLock() defer fake.shareServiceInstanceToSpacesMutex.RUnlock() fake.targetCFMutex.RLock() diff --git a/api/cloudcontroller/ccv3/internal/api_routes.go b/api/cloudcontroller/ccv3/internal/api_routes.go index 8f2239316c8..7029d8073fa 100644 --- a/api/cloudcontroller/ccv3/internal/api_routes.go +++ b/api/cloudcontroller/ccv3/internal/api_routes.go @@ -172,6 +172,7 @@ const ( PostUserRequest = "PostUser" PutTaskCancelRequest = "PutTaskCancel" SharePrivateDomainRequest = "SharePrivateDomainRequest" + ShareRouteRequest = "ShareRouteRequest" UnmapRouteRequest = "UnmapRoute" WhoAmI = "WhoAmI" ) @@ -277,6 +278,7 @@ var APIRoutes = map[string]Route{ MapRouteRequest: {Path: "/v3/routes/:route_guid/destinations", Method: http.MethodPost}, UnmapRouteRequest: {Path: "/v3/routes/:route_guid/destinations/:destination_guid", Method: http.MethodDelete}, PatchDestinationRequest: {Path: "/v3/routes/:route_guid/destinations/:destination_guid", Method: http.MethodPatch}, + ShareRouteRequest: {Path: "/v3/routes/:route_guid/relationships/shared_spaces", Method: http.MethodPost}, GetSecurityGroupsRequest: {Path: "/v3/security_groups", Method: http.MethodGet}, PostSecurityGroupRequest: {Path: "/v3/security_groups", Method: http.MethodPost}, DeleteSecurityGroupRequest: {Path: "/v3/security_groups/:security_group_guid", Method: http.MethodDelete}, diff --git a/api/cloudcontroller/ccv3/route.go b/api/cloudcontroller/ccv3/route.go index b40aed980c9..d7ad9a2c182 100644 --- a/api/cloudcontroller/ccv3/route.go +++ b/api/cloudcontroller/ccv3/route.go @@ -148,3 +148,28 @@ func (client Client) UpdateDestination(routeGUID string, destinationGUID string, }) return warnings, err } + +func (client Client) ShareRoute(routeGUID string, spaceGUID string) (Warnings, error) { + type space struct { + GUID string `json:"guid"` + } + + type body struct { + Data []space `json:"data"` + } + + requestBody := body{ + Data: []space{ + {GUID: spaceGUID}, + }, + } + + var responseBody resources.Build + _, warnings, err := client.MakeRequest(RequestParams{ + RequestName: internal.ShareRouteRequest, + URIParams: internal.Params{"route_guid": routeGUID}, + RequestBody: &requestBody, + ResponseBody: &responseBody, + }) + return warnings, err +} diff --git a/command/common/command_list_v7.go b/command/common/command_list_v7.go index 83300833d79..fada59bcb02 100644 --- a/command/common/command_list_v7.go +++ b/command/common/command_list_v7.go @@ -157,6 +157,7 @@ type commandList struct { SetStagingEnvironmentVariableGroup v7.SetStagingEnvironmentVariableGroupCommand `command:"set-staging-environment-variable-group" alias:"ssevg" description:"Pass parameters as JSON to create a staging environment variable group"` SharePrivateDomain v7.SharePrivateDomainCommand `command:"share-private-domain" description:"Share a private domain with a specific org"` ShareService v7.ShareServiceCommand `command:"share-service" description:"Share a service instance with another space"` + ShareRoute v7.ShareRouteCommand `command:"share-route" description:"Share a route in between spaces"` Space v7.SpaceCommand `command:"space" description:"Show space info"` SpaceQuota v7.SpaceQuotaCommand `command:"space-quota" description:"Show space quota info"` SpaceQuotas v7.SpaceQuotasCommand `command:"space-quotas" description:"List available space quotas"` diff --git a/command/common/internal/help_all_display.go b/command/common/internal/help_all_display.go index e6d19c3d859..8c6e9957f09 100644 --- a/command/common/internal/help_all_display.go +++ b/command/common/internal/help_all_display.go @@ -68,6 +68,7 @@ var HelpCategoryList = []HelpCategory{ {"create-route", "check-route", "map-route", "unmap-route", "delete-route"}, {"delete-orphaned-routes"}, {"update-destination"}, + {"share-route"}, }, }, { diff --git a/command/v7/actor.go b/command/v7/actor.go index b62365e4a90..64ef63dd1f0 100644 --- a/command/v7/actor.go +++ b/command/v7/actor.go @@ -216,6 +216,7 @@ type Actor interface { SetTarget(settings v7action.TargetSettings) (v7action.Warnings, error) SharePrivateDomain(domainName string, orgName string) (v7action.Warnings, error) ShareServiceInstanceToSpaceAndOrg(serviceInstanceName, targetedSpaceGUID, targetedOrgGUID string, sharedToDetails v7action.ServiceInstanceSharingParams) (v7action.Warnings, error) + ShareRoute(routeGUID string, spaceGUID string) (v7action.Warnings, error) StageApplicationPackage(pkgGUID string) (resources.Build, v7action.Warnings, error) StagePackage(packageGUID, appName, spaceGUID string) (<-chan resources.Droplet, <-chan v7action.Warnings, <-chan error) StartApplication(appGUID string) (v7action.Warnings, error) diff --git a/command/v7/share_route_command.go b/command/v7/share_route_command.go new file mode 100644 index 00000000000..b1fdb2b6880 --- /dev/null +++ b/command/v7/share_route_command.go @@ -0,0 +1,101 @@ +package v7 + +import ( + "code.cloudfoundry.org/cli/actor/actionerror" + "code.cloudfoundry.org/cli/command/flag" +) + +type ShareRouteCommand struct { + BaseCommand + + RequireArgs flag.Domain `positional-args:"yes"` + Hostname string `long:"hostname" short:"n" description:"Hostname for the HTTP route (required for shared domains)"` + Path flag.V7RoutePath `long:"path" description:"Path for the HTTP route"` + DestinationOrg string `short:"o" description:"The org of the destination app (Default: targeted org)"` + DestinationSpace string `short:"s" description:"The space of the destination app (Default: targeted space)"` + + relatedCommands interface{} `related_commands:"create-route, map-route, unmap-route, routes"` +} + +func (cmd ShareRouteCommand) Usage() string { + return ` +Share an existing route in between two spaces: + CF_NAME share-route DOMAIN [--hostname HOSTNAME] [--path PATH] -s OTHER_SPACE [-o OTHER_ORG]` +} + +func (cmd ShareRouteCommand) Examples() string { + return ` +CF_NAME share-route example.com --hostname myHost --path foo -s TargetSpace -o TargetOrg # myhost.example.com/foo +CF_NAME share-route example.com --hostname myHost -s TargetSpace # myhost.example.com +CF_NAME share-route example.com --hostname myHost -s TargetSpace -o TargetOrg # myhost.example.com` +} + +func (cmd ShareRouteCommand) Execute(args []string) error { + err := cmd.SharedActor.CheckTarget(true, true) + if err != nil { + return err + } + + user, err := cmd.Actor.GetCurrentUser() + if err != nil { + return err + } + + domain, warnings, err := cmd.Actor.GetDomainByName(cmd.RequireArgs.Domain) + cmd.UI.DisplayWarnings(warnings) + if err != nil { + return err + } + + path := cmd.Path.Path + route, warnings, err := cmd.Actor.GetRouteByAttributes(domain, cmd.Hostname, path, 0) + cmd.UI.DisplayWarnings(warnings) + if err != nil { + if _, ok := err.(actionerror.RouteNotFoundError); ok { + cmd.UI.DisplayText("Can not share route:") + return err + } + } + + destinationOrgName := cmd.DestinationOrg + + if destinationOrgName == "" { + destinationOrgName = cmd.Config.TargetedOrganizationName() + } + + destinationOrg, warnings, err := cmd.Actor.GetOrganizationByName(destinationOrgName) + + if err != nil { + if _, ok := err.(actionerror.OrganizationNotFoundError); ok { + cmd.UI.DisplayText("Can not share route:") + return err + } + } + + targetedSpace, warnings, err := cmd.Actor.GetSpaceByNameAndOrganization(cmd.DestinationSpace, destinationOrg.GUID) + if err != nil { + if _, ok := err.(actionerror.SpaceNotFoundError); ok { + cmd.UI.DisplayText("Can not share route:") + return err + } + } + + url := desiredURL(domain.Name, cmd.Hostname, path, 0) + cmd.UI.DisplayTextWithFlavor("Sharing route {{.URL}} to space {{.DestinationSpace}} as {{.User}}", + map[string]interface{}{ + "URL": url, + "DestinationSpace": cmd.DestinationSpace, + "User": user.Name, + }) + warnings, err = cmd.Actor.ShareRoute( + route.GUID, + targetedSpace.GUID, + ) + cmd.UI.DisplayWarnings(warnings) + if err != nil { + return err + } + cmd.UI.DisplayOK() + + return nil +} diff --git a/command/v7/share_route_command_test.go b/command/v7/share_route_command_test.go new file mode 100644 index 00000000000..220efdafb30 --- /dev/null +++ b/command/v7/share_route_command_test.go @@ -0,0 +1,279 @@ +package v7_test + +import ( + "code.cloudfoundry.org/cli/actor/actionerror" + "code.cloudfoundry.org/cli/actor/v7action" + "code.cloudfoundry.org/cli/cf/errors" + "code.cloudfoundry.org/cli/command/commandfakes" + "code.cloudfoundry.org/cli/command/flag" + v7 "code.cloudfoundry.org/cli/command/v7" + "code.cloudfoundry.org/cli/command/v7/v7fakes" + "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/configv3" + "code.cloudfoundry.org/cli/util/ui" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gbytes" +) + +var _ = Describe("share-route Command", func() { + var ( + cmd v7.ShareRouteCommand + testUI *ui.UI + fakeConfig *commandfakes.FakeConfig + fakeSharedActor *commandfakes.FakeSharedActor + fakeActor *v7fakes.FakeActor + binaryName string + executeErr error + domainName string + orgName string + spaceName string + hostname string + path string + ) + + BeforeEach(func() { + testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) + fakeConfig = new(commandfakes.FakeConfig) + fakeSharedActor = new(commandfakes.FakeSharedActor) + fakeActor = new(v7fakes.FakeActor) + + binaryName = "myBinaryBread" + fakeConfig.BinaryNameReturns(binaryName) + + domainName = "some-domain.com" + orgName = "org-name-a" + spaceName = "space-name-a" + hostname = "myHostname" + path = "myPath" + + cmd = v7.ShareRouteCommand{ + BaseCommand: v7.BaseCommand{ + UI: testUI, + Config: fakeConfig, + SharedActor: fakeSharedActor, + Actor: fakeActor, + }, + RequireArgs: flag.Domain{Domain: domainName}, + Hostname: hostname, + Path: flag.V7RoutePath{Path: path}, + DestinationOrg: orgName, + DestinationSpace: spaceName, + } + + fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "some-space", GUID: "some-space-guid"}) + fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org"}) + fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + }) + + JustBeforeEach(func() { + executeErr = cmd.Execute(nil) + }) + + It("checks that target", func() { + Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) + checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) + Expect(checkTargetedOrg).To(BeTrue()) + Expect(checkTargetedSpace).To(BeTrue()) + }) + + When("checking target fails", func() { + BeforeEach(func() { + fakeSharedActor.CheckTargetReturns(actionerror.NoOrganizationTargetedError{BinaryName: binaryName}) + }) + It("returns an error", func() { + Expect(executeErr).To(MatchError(actionerror.NoOrganizationTargetedError{BinaryName: binaryName})) + + Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) + checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) + Expect(checkTargetedOrg).To(BeTrue()) + Expect(checkTargetedSpace).To(BeTrue()) + }) + }) + + When("the user is not logged in", func() { + var expectedErr error + + BeforeEach(func() { + expectedErr = errors.New("some current user error") + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) + }) + + It("return an error", func() { + Expect(executeErr).To(Equal(expectedErr)) + }) + }) + + When("the user is logged in and targeted", func() { + When("getting the domain errors", func() { + BeforeEach(func() { + fakeActor.GetDomainByNameReturns(resources.Domain{}, v7action.Warnings{"get-domain-warnings"}, errors.New("get-domain-error")) + }) + + It("returns the error and displays warnings", func() { + Expect(testUI.Err).To(Say("get-domain-warnings")) + Expect(executeErr).To(MatchError(errors.New("get-domain-error"))) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(0)) + + Expect(fakeActor.GetSpaceByNameAndOrganizationCallCount()).To(Equal(0)) + + Expect(fakeActor.ShareRouteCallCount()).To(Equal(0)) + }) + }) + + When("getting the domain succeeds", func() { + BeforeEach(func() { + fakeActor.GetDomainByNameReturns( + resources.Domain{Name: domainName, GUID: "domain-guid"}, + v7action.Warnings{"get-domain-warnings"}, + nil, + ) + }) + + When("the requested route does not exist", func() { + BeforeEach(func() { + fakeActor.GetRouteByAttributesReturns( + resources.Route{}, + v7action.Warnings{"get-route-warnings"}, + actionerror.RouteNotFoundError{}, + ) + }) + + It("displays error message", func() { + Expect(testUI.Err).To(Say("get-domain-warnings")) + Expect(testUI.Err).To(Say("get-route-warnings")) + Expect(executeErr).To(HaveOccurred()) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + }) + }) + + When("the requested route exists", func() { + BeforeEach(func() { + fakeActor.GetRouteByAttributesReturns( + resources.Route{GUID: "route-guid"}, + v7action.Warnings{"get-route-warnings"}, + nil, + ) + }) + When("getting the target space errors", func() { + BeforeEach(func() { + fakeActor.GetOrganizationByNameReturns( + resources.Organization{GUID: "org-guid-a"}, + v7action.Warnings{"get-route-warnings"}, + nil, + ) + fakeActor.GetSpaceByNameAndOrganizationReturns( + resources.Space{}, + v7action.Warnings{"get-route-warnings"}, + actionerror.SpaceNotFoundError{}, + ) + }) + It("returns the error and warnings", func() { + Expect(executeErr).To(HaveOccurred()) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + + Expect(fakeActor.GetOrganizationByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetOrganizationByNameArgsForCall(0)).To(Equal(orgName)) + Expect(fakeActor.GetSpaceByNameAndOrganizationCallCount()).To(Equal(1)) + spaceName, orgGuid := fakeActor.GetSpaceByNameAndOrganizationArgsForCall(0) + Expect(spaceName).To(Equal("space-name-a")) + Expect(orgGuid).To(Equal("org-guid-a")) + + Expect(fakeActor.ShareRouteCallCount()).To(Equal(0)) + }) + }) + When("getting the target org errors", func() { + BeforeEach(func() { + fakeActor.GetOrganizationByNameReturns( + resources.Organization{}, + v7action.Warnings{"get-route-warnings"}, + actionerror.OrganizationNotFoundError{}, + ) + }) + It("returns the error and warnings", func() { + Expect(executeErr).To(HaveOccurred()) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + + Expect(fakeActor.GetOrganizationByNameCallCount()).To(Equal(1)) + orgName := fakeActor.GetOrganizationByNameArgsForCall(0) + Expect(orgName).To(Equal("org-name-a")) + + Expect(fakeActor.ShareRouteCallCount()).To(Equal(0)) + }) + }) + When("getting the target space succeeds", func() { + BeforeEach(func() { + fakeActor.GetOrganizationByNameReturns( + resources.Organization{GUID: "org-guid-a"}, + v7action.Warnings{"get-route-warnings"}, + nil, + ) + fakeActor.GetSpaceByNameAndOrganizationReturns( + resources.Space{GUID: "space-guid-b"}, + v7action.Warnings{"get-route-warnings"}, + nil, + ) + }) + It("exits 0 with helpful message that the route is now being shared", func() { + Expect(executeErr).ShouldNot(HaveOccurred()) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + + Expect(fakeActor.GetOrganizationByNameCallCount()).To(Equal(1)) + orgName := fakeActor.GetOrganizationByNameArgsForCall(0) + Expect(orgName).To(Equal("org-name-a")) + + Expect(fakeActor.GetSpaceByNameAndOrganizationCallCount()).To(Equal(1)) + spaceName, orgGuid := fakeActor.GetSpaceByNameAndOrganizationArgsForCall(0) + Expect(spaceName).To(Equal("space-name-a")) + Expect(orgGuid).To(Equal("org-guid-a")) + Expect(fakeActor.ShareRouteCallCount()).To(Equal(1)) + }) + }) + }) + }) + }) +}) diff --git a/command/v7/v7fakes/fake_actor.go b/command/v7/v7fakes/fake_actor.go index 523de5ea272..1a950e4692e 100644 --- a/command/v7/v7fakes/fake_actor.go +++ b/command/v7/v7fakes/fake_actor.go @@ -2957,6 +2957,20 @@ type FakeActor struct { result1 v7action.Warnings result2 error } + ShareRouteStub func(string, string) (v7action.Warnings, error) + shareRouteMutex sync.RWMutex + shareRouteArgsForCall []struct { + arg1 string + arg2 string + } + shareRouteReturns struct { + result1 v7action.Warnings + result2 error + } + shareRouteReturnsOnCall map[int]struct { + result1 v7action.Warnings + result2 error + } ShareServiceInstanceToSpaceAndOrgStub func(string, string, string, v7action.ServiceInstanceSharingParams) (v7action.Warnings, error) shareServiceInstanceToSpaceAndOrgMutex sync.RWMutex shareServiceInstanceToSpaceAndOrgArgsForCall []struct { @@ -16243,6 +16257,70 @@ func (fake *FakeActor) SharePrivateDomainReturnsOnCall(i int, result1 v7action.W }{result1, result2} } +func (fake *FakeActor) ShareRoute(arg1 string, arg2 string) (v7action.Warnings, error) { + fake.shareRouteMutex.Lock() + ret, specificReturn := fake.shareRouteReturnsOnCall[len(fake.shareRouteArgsForCall)] + fake.shareRouteArgsForCall = append(fake.shareRouteArgsForCall, struct { + arg1 string + arg2 string + }{arg1, arg2}) + fake.recordInvocation("ShareRoute", []interface{}{arg1, arg2}) + fake.shareRouteMutex.Unlock() + if fake.ShareRouteStub != nil { + return fake.ShareRouteStub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.shareRouteReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeActor) ShareRouteCallCount() int { + fake.shareRouteMutex.RLock() + defer fake.shareRouteMutex.RUnlock() + return len(fake.shareRouteArgsForCall) +} + +func (fake *FakeActor) ShareRouteCalls(stub func(string, string) (v7action.Warnings, error)) { + fake.shareRouteMutex.Lock() + defer fake.shareRouteMutex.Unlock() + fake.ShareRouteStub = stub +} + +func (fake *FakeActor) ShareRouteArgsForCall(i int) (string, string) { + fake.shareRouteMutex.RLock() + defer fake.shareRouteMutex.RUnlock() + argsForCall := fake.shareRouteArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeActor) ShareRouteReturns(result1 v7action.Warnings, result2 error) { + fake.shareRouteMutex.Lock() + defer fake.shareRouteMutex.Unlock() + fake.ShareRouteStub = nil + fake.shareRouteReturns = struct { + result1 v7action.Warnings + result2 error + }{result1, result2} +} + +func (fake *FakeActor) ShareRouteReturnsOnCall(i int, result1 v7action.Warnings, result2 error) { + fake.shareRouteMutex.Lock() + defer fake.shareRouteMutex.Unlock() + fake.ShareRouteStub = nil + if fake.shareRouteReturnsOnCall == nil { + fake.shareRouteReturnsOnCall = make(map[int]struct { + result1 v7action.Warnings + result2 error + }) + } + fake.shareRouteReturnsOnCall[i] = struct { + result1 v7action.Warnings + result2 error + }{result1, result2} +} + func (fake *FakeActor) ShareServiceInstanceToSpaceAndOrg(arg1 string, arg2 string, arg3 string, arg4 v7action.ServiceInstanceSharingParams) (v7action.Warnings, error) { fake.shareServiceInstanceToSpaceAndOrgMutex.Lock() ret, specificReturn := fake.shareServiceInstanceToSpaceAndOrgReturnsOnCall[len(fake.shareServiceInstanceToSpaceAndOrgArgsForCall)] @@ -19312,6 +19390,8 @@ func (fake *FakeActor) Invocations() map[string][][]interface{} { defer fake.setTargetMutex.RUnlock() fake.sharePrivateDomainMutex.RLock() defer fake.sharePrivateDomainMutex.RUnlock() + fake.shareRouteMutex.RLock() + defer fake.shareRouteMutex.RUnlock() fake.shareServiceInstanceToSpaceAndOrgMutex.RLock() defer fake.shareServiceInstanceToSpaceAndOrgMutex.RUnlock() fake.stageApplicationPackageMutex.RLock() diff --git a/integration/v7/isolated/share_route_command_test.go b/integration/v7/isolated/share_route_command_test.go new file mode 100644 index 00000000000..d3f8affe88b --- /dev/null +++ b/integration/v7/isolated/share_route_command_test.go @@ -0,0 +1,204 @@ +package isolated + +import ( + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" + . "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers" + "code.cloudfoundry.org/cli/integration/helpers" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gbytes" + . "github.com/onsi/gomega/gexec" +) + +var _ = Describe("share route command", func() { + Context("Help", func() { + It("appears in cf help -a", func() { + session := helpers.CF("help", "-a") + + Eventually(session).Should(Exit(0)) + Expect(session).To(HaveCommandInCategoryWithDescription("share-route", "ROUTES", "Share a route in between spaces")) + }) + + It("displays the help information", func() { + session := helpers.CF("share-route", "--help") + Eventually(session).Should(Say(`NAME:`)) + Eventually(session).Should(Say("share-route - Share a route in between spaces")) + Eventually(session).Should(Say(`\n`)) + + Eventually(session).Should(Say(`USAGE:`)) + Eventually(session).Should(Say(`Share an existing route in between two spaces:`)) + Eventually(session).Should(Say(`cf share-route DOMAIN \[--hostname HOSTNAME\] \[--path PATH\] -s OTHER_SPACE \[-o OTHER_ORG\]`)) + Eventually(session).Should(Say(`\n`)) + + Eventually(session).Should(Say(`EXAMPLES:`)) + Eventually(session).Should(Say(`cf share-route example.com --hostname myHost --path foo -s TargetSpace -o TargetOrg # myhost.example.com/foo`)) + Eventually(session).Should(Say(`cf share-route example.com --hostname myHost -s TargetSpace # myhost.example.com`)) + Eventually(session).Should(Say(`cf share-route example.com --hostname myHost -s TargetSpace -o TargetOrg # myhost.example.com`)) + Eventually(session).Should(Say(`\n`)) + + Eventually(session).Should(Say(`OPTIONS:`)) + Eventually(session).Should(Say(`--hostname, -n\s+Hostname for the HTTP route \(required for shared domains\)`)) + Eventually(session).Should(Say(`--path\s+Path for the HTTP route`)) + Eventually(session).Should(Say(`-o\s+The org of the destination app \(Default: targeted org\)`)) + Eventually(session).Should(Say(`-s\s+The space of the destination app \(Default: targeted space\)`)) + Eventually(session).Should(Say(`\n`)) + + Eventually(session).Should(Say(`SEE ALSO:`)) + Eventually(session).Should(Say(`create-route, map-route, routes, unmap-route`)) + + Eventually(session).Should(Exit(0)) + }) + }) + + When("the environment is not setup correctly", func() { + It("fails with the appropriate errors", func() { + helpers.CheckEnvironmentTargetedCorrectly(true, false, ReadOnlyOrg, "share-route", "some-domain", "-s SOME_SPACE") + }) + }) + + When("the environment is set up conrrectly", func() { + var ( + userName string + orgName string + spaceName string + ) + + BeforeEach(func() { + helpers.SkipIfVersionLessThan(ccversion.MinVersionHTTP2RoutingV3) + orgName = helpers.NewOrgName() + spaceName = helpers.NewSpaceName() + + helpers.SetupCF(orgName, spaceName) + userName, _ = helpers.GetCredentials() + }) + + AfterEach(func() { + helpers.QuickDeleteOrg(orgName) + }) + + When("the domain extists", func() { + var ( + domainName string + targetSpaceName string + ) + + BeforeEach(func() { + domainName = helpers.NewDomainName() + }) + + When("the route exists", func() { + var ( + domain helpers.Domain + hostname string + ) + When("the target space exists in targeted org", func() { + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "panera-bread" + targetSpaceName = helpers.NewSpaceName() + helpers.CreateSpace(targetSpaceName) + domain.Create() + Eventually(helpers.CF("create-route", domain.Name, "--hostname", hostname)).Should(Exit(0)) + }) + + AfterEach(func() { + domain.Delete() + }) + + It("shares the route to the destination space", func() { + session := helpers.CF("share-route", domainName, "--hostname", hostname, "-s", targetSpaceName) + Eventually(session).Should(Say(`Sharing route %s.%s to space %s as %s`, hostname, domainName, targetSpaceName, userName)) + Eventually(session).Should(Say(`OK`)) + Eventually(session).Should(Exit(0)) + }) + }) + + When("the target organization does not exist", func() { + var targetOrgName string + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "panera-bread" + targetSpaceName = helpers.NewSpaceName() + targetOrgName = helpers.NewOrgName() + domain.Create() + Eventually(helpers.CF("create-route", domain.Name, "--hostname", hostname)).Should(Exit(0)) + }) + + It("exists with 1 and an error message", func() { + session := helpers.CF("share-route", domainName, "--hostname", hostname, "-o", targetOrgName, "-s", targetSpaceName) + Eventually(session).Should(Say("Can not share route:")) + Eventually(session).Should(Say(`FAILED`)) + Eventually(session).Should(Exit(1)) + }) + }) + + When("the target space exists in another existing org", func() { + var targetOrgName string + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "menchies-icecream" + targetOrgName = helpers.NewOrgName() + targetSpaceName = helpers.NewSpaceName() + helpers.CreateOrgAndSpace(targetOrgName, targetSpaceName) + helpers.SetupCF(orgName, spaceName) + domain.Create() + Eventually(helpers.CF("create-route", domain.Name, "--hostname", hostname)).Should(Exit(0)) + }) + + AfterEach(func() { + domain.Delete() + }) + + It("shared the route to the destination space", func() { + session := helpers.CF("share-route", domainName, "--hostname", hostname, "-o", targetOrgName, "-s", targetSpaceName) + Eventually(session).Should(Say(`Sharing route %s.%s to space %s as %s`, hostname, domainName, targetSpaceName, userName)) + Eventually(session).Should(Say(`OK`)) + Eventually(session).Should(Exit(0)) + }) + }) + + When("the space does not exist", func() { + var destinationSpaceName string + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "menchies-icecream" + destinationSpaceName = "doesNotExistSpace" + domain.Create() + Eventually(helpers.CF("create-route", domain.Name, "--hostname", hostname)).Should(Exit(0)) + }) + + It("exists with 1 with an error", func() { + session := helpers.CF("share-route", domainName, "--hostname", hostname, "-s", destinationSpaceName) + Eventually(session).Should(Say("Can not share route:")) + Eventually(session).Should(Say(`FAILED`)) + Eventually(session).Should(Exit(1)) + }) + }) + }) + + When("the route does not exist", func() { + var ( + domain helpers.Domain + hostname string + ) + + When("the target space exists", func() { + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "panera-bread" + targetSpaceName = helpers.NewSpaceName() + helpers.CreateSpace(targetSpaceName) + domain.Create() + }) + + It("exits with 1 with an error message", func() { + session := helpers.CF("share-route", domainName, "--hostname", hostname, "-s", targetSpaceName) + Eventually(session).Should(Say("Can not share route:")) + Eventually(session).Should(Say(`FAILED`)) + Eventually(session).Should(Exit(1)) + }) + }) + }) + }) + }) +}) From aa71003bd2701c5a615781a0e4f84e0bfcd9db78 Mon Sep 17 00:00:00 2001 From: Julian Hjortshoj Date: Thu, 18 Aug 2022 15:49:12 -0700 Subject: [PATCH 039/248] Add support for Korifi to the `auth` command (#2296) --- command/v7/auth_command.go | 26 ++++++++++++- command/v7/auth_command_test.go | 65 ++++++++++++++++++++++++++++++--- 2 files changed, 84 insertions(+), 7 deletions(-) diff --git a/command/v7/auth_command.go b/command/v7/auth_command.go index 0b03acd0a1e..6b787b3245f 100644 --- a/command/v7/auth_command.go +++ b/command/v7/auth_command.go @@ -1,6 +1,7 @@ package v7 import ( + "errors" "fmt" "code.cloudfoundry.org/cli/api/uaa/constant" @@ -77,6 +78,29 @@ func (cmd AuthCommand) Execute(args []string) error { grantType = constant.GrantTypeClientCredentials credentials["client_id"] = username credentials["client_secret"] = password + } else if cmd.Config.IsCFOnK8s() { + prompts, err := cmd.Actor.GetLoginPrompts() + if err != nil { + return err + } + prompt, ok := prompts["k8s-auth-info"] + if !ok { + return errors.New("kubernetes login context is missing") + } + + userFound := false + for _, val := range prompt.Entries { + if val == username { + userFound = true + break + } + } + if !userFound { + return errors.New("kubernetes user not found in configuration: " + username) + } + credentials = map[string]string{ + "k8s-auth-info": username, + } } else { credentials = map[string]string{ "username": username, @@ -118,7 +142,7 @@ func (cmd AuthCommand) getUsernamePassword() (string, string, error) { if password == "" { if envPassword := cmd.Config.CFPassword(); envPassword != "" { password = envPassword - } else { + } else if !cmd.Config.IsCFOnK8s() { passwordMissing = true } } diff --git a/command/v7/auth_command_test.go b/command/v7/auth_command_test.go index 152c648a3c9..682aa965bca 100644 --- a/command/v7/auth_command_test.go +++ b/command/v7/auth_command_test.go @@ -1,6 +1,7 @@ package v7_test import ( + "code.cloudfoundry.org/cli/cf/configuration/coreconfig" "errors" "code.cloudfoundry.org/cli/api/uaa" @@ -18,12 +19,13 @@ import ( var _ = Describe("auth Command", func() { var ( - cmd AuthCommand - testUI *ui.UI - fakeActor *v7fakes.FakeActor - fakeConfig *commandfakes.FakeConfig - binaryName string - err error + cmd AuthCommand + testUI *ui.UI + fakeActor *v7fakes.FakeActor + fakeConfig *commandfakes.FakeConfig + binaryName string + err error + k8sLoginPrompts map[string]coreconfig.AuthPrompt ) BeforeEach(func() { @@ -43,6 +45,11 @@ var _ = Describe("auth Command", func() { fakeConfig.BinaryNameReturns(binaryName) fakeConfig.UAAOAuthClientReturns("cf") fakeConfig.APIVersionReturns("3.99.0") + k8sLoginPrompts = map[string]coreconfig.AuthPrompt{ + "k8s-auth-info": { + Entries: []string{"myuser"}, + }, + } }) JustBeforeEach(func() { @@ -113,6 +120,17 @@ var _ = Describe("auth Command", func() { MissingPassword: true, })) }) + + When("authenticating against Korifi", func() { + BeforeEach(func() { + fakeConfig.IsCFOnK8sReturns(true) + fakeActor.GetLoginPromptsReturns(k8sLoginPrompts, nil) + }) + + It("succeeds", func() { + Expect(err).NotTo(HaveOccurred()) + }) + }) }) }) @@ -298,6 +316,41 @@ var _ = Describe("auth Command", func() { }) }) }) + + When("authenticating against Korifi", func() { + BeforeEach(func() { + cmd.RequiredArgs.Username = "myuser" + fakeConfig.IsCFOnK8sReturns(true) + fakeActor.GetLoginPromptsReturns(k8sLoginPrompts, nil) + }) + + When("the specified username doesn't match any k8s context", func() { + BeforeEach(func() { + cmd.RequiredArgs.Username = "some-unknown-user" + }) + + It("errors", func() { + Expect(err).To(MatchError(errors.New("kubernetes user not found in configuration: some-unknown-user"))) + }) + }) + + When("the prompts don't contain k8s authentication information", func() { + BeforeEach(func() { + k8sLoginPrompts = map[string]coreconfig.AuthPrompt{ + "some-other-auth-info": { + Entries: []string{"myuser"}, + }, + } + fakeActor.GetLoginPromptsReturns(k8sLoginPrompts, nil) + }) + + It("errors", func() { + Expect(err).To(MatchError(errors.New("kubernetes login context is missing"))) + }) + + }) + + }) }) When("a user has manually added their client credentials to the config file", func() { From 6270f997b99b0ef32af13a4b05d30b06ca5f8da2 Mon Sep 17 00:00:00 2001 From: Andrew Wittrock Date: Thu, 14 Jul 2022 15:47:54 -0700 Subject: [PATCH 040/248] Refresh token in logs is disabled for Korifi - Configured with `Config.IsCFOnK8s` Co-authored-by: Clint Yoshimura --- command/v7/logs_command.go | 23 +++++++++++++---------- command/v7/logs_command_test.go | 10 ++++++++++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/command/v7/logs_command.go b/command/v7/logs_command.go index b2506240752..fea41976cc3 100644 --- a/command/v7/logs_command.go +++ b/command/v7/logs_command.go @@ -58,20 +58,23 @@ func (cmd LogsCommand) Execute(args []string) error { return cmd.displayRecentLogs() } - stop := make(chan struct{}) - stoppedRefreshing := make(chan struct{}) - stoppedOutputtingRefreshErrors := make(chan struct{}) - err = cmd.refreshTokenPeriodically(stop, stoppedRefreshing, stoppedOutputtingRefreshErrors) - if err != nil { - return err + if !cmd.Config.IsCFOnK8s() { + stop := make(chan struct{}) + stoppedRefreshing := make(chan struct{}) + stoppedOutputtingRefreshErrors := make(chan struct{}) + err = cmd.refreshTokenPeriodically(stop, stoppedRefreshing, stoppedOutputtingRefreshErrors) + if err != nil { + return err + } + defer func() { + close(stop) + <-stoppedRefreshing + <-stoppedOutputtingRefreshErrors + }() } err = cmd.streamLogs() - close(stop) - <-stoppedRefreshing - <-stoppedOutputtingRefreshErrors - return err } diff --git a/command/v7/logs_command_test.go b/command/v7/logs_command_test.go index ea188379989..034257bb707 100644 --- a/command/v7/logs_command_test.go +++ b/command/v7/logs_command_test.go @@ -248,6 +248,16 @@ var _ = Describe("logs command", func() { }) }) + When("isCFOnK8s is true", func() { + BeforeEach(func() { + fakeConfig.IsCFOnK8sReturns(true) + }) + + It("does not call ScheduleTokenRefresh", func() { + Expect(fakeActor.ScheduleTokenRefreshCallCount()).To(Equal(0)) + }) + }) + It("displays the error and all warnings", func() { Expect(executeErr).NotTo(HaveOccurred()) Expect(testUI.Err).To(Say("steve for all I care")) From ac80d76cfa553487c69ab6752bff58de5ac7bce4 Mon Sep 17 00:00:00 2001 From: Shwetha Gururaj Date: Wed, 24 Aug 2022 11:20:03 -0400 Subject: [PATCH 041/248] feat: Add move-route command to cf cli (#2302) (#2307) * feat: Add transfer-route-owner command to cf cli Co-authored-by: Shwetha Gururaj * feat: update repository variable. Update workflow action * fix: remove windows 2016, swap to windows latest. Fix relative file path * chore: windows values * chore: swap to Rel instead of join * chore: main dir * chore: join on current dir * chore: clean path first * chore: try from slash * chore: remove dot syntax * chore: swap to move-route Co-authored-by: Shwetha Gururaj * chore: windows tests again * chore: remove test println * chore: update path to /relationships/space from transferowner Co-authored-by: Shwetha Gururaj * Change display text * Remove focus * Fix typo * Send non-array data in requestBody * Change message ordering * Create shared domain instead of private Co-authored-by: Shwetha Gururaj Co-authored-by: Peter Levine --- .github/workflows/code-quality.yml | 2 +- .github/workflows/units.yml | 9 +- actor/v7action/cloud_controller_client.go | 1 + actor/v7action/route.go | 5 + .../fake_cloud_controller_client.go | 80 +++++ .../handle_app_path_override_test.go | 7 +- .../ccv3/internal/api_routes.go | 2 + api/cloudcontroller/ccv3/route.go | 25 ++ command/common/command_list_v7.go | 1 + command/common/internal/help_all_display.go | 1 + command/v7/actor.go | 1 + command/v7/move_route_command.go | 101 +++++++ command/v7/move_route_command_test.go | 279 ++++++++++++++++++ command/v7/v7fakes/fake_actor.go | 80 +++++ .../v7/isolated/move_route_command_test.go | 204 +++++++++++++ 15 files changed, 789 insertions(+), 9 deletions(-) create mode 100644 command/v7/move_route_command.go create mode 100644 command/v7/move_route_command_test.go create mode 100644 integration/v7/isolated/move_route_command_test.go diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index e404f2dc45a..b37b1bef652 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -12,7 +12,7 @@ jobs: analyze: name: Analyze runs-on: ubuntu-latest - if: ${{ github.action_repository == 'cloudfoundry/cli' }} + if: ${{ github.repository == 'cloudfoundry/cli' }} permissions: actions: read contents: read diff --git a/.github/workflows/units.yml b/.github/workflows/units.yml index db2f329155e..55b534dc9c0 100644 --- a/.github/workflows/units.yml +++ b/.github/workflows/units.yml @@ -1,10 +1,6 @@ name: Units Tests -on: - push: - branches: - - "*" - +on: [push] permissions: contents: write @@ -83,9 +79,8 @@ jobs: strategy: matrix: os: - - windows-2022 + - windows-latest - windows-2019 - - windows-2016 runs-on: ${{ matrix.os }} needs: shared-values defaults: diff --git a/actor/v7action/cloud_controller_client.go b/actor/v7action/cloud_controller_client.go index 756c0528ffd..050b4d5fdac 100644 --- a/actor/v7action/cloud_controller_client.go +++ b/actor/v7action/cloud_controller_client.go @@ -140,6 +140,7 @@ type CloudControllerClient interface { GetUsers(query ...ccv3.Query) ([]resources.User, ccv3.Warnings, error) MakeRequestSendReceiveRaw(Method string, URL string, headers http.Header, requestBody []byte) ([]byte, *http.Response, error) MapRoute(routeGUID string, appGUID string, destinationProtocol string) (ccv3.Warnings, error) + MoveRoute(routeGUID string, spaceGUID string) (ccv3.Warnings, error) PollJob(jobURL ccv3.JobURL) (ccv3.Warnings, error) PollJobForState(jobURL ccv3.JobURL, state constant.JobState) (ccv3.Warnings, error) PollJobToEventStream(jobURL ccv3.JobURL) chan ccv3.PollJobEvent diff --git a/actor/v7action/route.go b/actor/v7action/route.go index 16f7bc9f4ce..7cac6180001 100644 --- a/actor/v7action/route.go +++ b/actor/v7action/route.go @@ -426,6 +426,11 @@ func (actor Actor) GetApplicationRoutes(appGUID string) ([]resources.Route, Warn return routes, allWarnings, nil } +func (actor Actor) MoveRoute(routeGUID string, spaceGUID string) (Warnings, error) { + warnings, err := actor.CloudControllerClient.MoveRoute(routeGUID, spaceGUID) + return Warnings(warnings), err +} + func getDomainName(fullURL, host, path string, port int) string { domainWithoutHost := strings.TrimPrefix(fullURL, host+".") domainWithoutPath := strings.TrimSuffix(domainWithoutHost, path) diff --git a/actor/v7action/v7actionfakes/fake_cloud_controller_client.go b/actor/v7action/v7actionfakes/fake_cloud_controller_client.go index 15a378271c2..8b2d4240737 100644 --- a/actor/v7action/v7actionfakes/fake_cloud_controller_client.go +++ b/actor/v7action/v7actionfakes/fake_cloud_controller_client.go @@ -1966,6 +1966,20 @@ type FakeCloudControllerClient struct { result1 ccv3.Warnings result2 error } + MoveRouteStub func(string, string) (ccv3.Warnings, error) + moveRouteMutex sync.RWMutex + moveRouteArgsForCall []struct { + arg1 string + arg2 string + } + moveRouteReturns struct { + result1 ccv3.Warnings + result2 error + } + moveRouteReturnsOnCall map[int]struct { + result1 ccv3.Warnings + result2 error + } PollJobStub func(ccv3.JobURL) (ccv3.Warnings, error) pollJobMutex sync.RWMutex pollJobArgsForCall []struct { @@ -11192,6 +11206,70 @@ func (fake *FakeCloudControllerClient) MapRouteReturnsOnCall(i int, result1 ccv3 }{result1, result2} } +func (fake *FakeCloudControllerClient) MoveRoute(arg1 string, arg2 string) (ccv3.Warnings, error) { + fake.moveRouteMutex.Lock() + ret, specificReturn := fake.moveRouteReturnsOnCall[len(fake.moveRouteArgsForCall)] + fake.moveRouteArgsForCall = append(fake.moveRouteArgsForCall, struct { + arg1 string + arg2 string + }{arg1, arg2}) + fake.recordInvocation("MoveRoute", []interface{}{arg1, arg2}) + fake.moveRouteMutex.Unlock() + if fake.MoveRouteStub != nil { + return fake.MoveRouteStub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.moveRouteReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeCloudControllerClient) MoveRouteCallCount() int { + fake.moveRouteMutex.RLock() + defer fake.moveRouteMutex.RUnlock() + return len(fake.moveRouteArgsForCall) +} + +func (fake *FakeCloudControllerClient) MoveRouteCalls(stub func(string, string) (ccv3.Warnings, error)) { + fake.moveRouteMutex.Lock() + defer fake.moveRouteMutex.Unlock() + fake.MoveRouteStub = stub +} + +func (fake *FakeCloudControllerClient) MoveRouteArgsForCall(i int) (string, string) { + fake.moveRouteMutex.RLock() + defer fake.moveRouteMutex.RUnlock() + argsForCall := fake.moveRouteArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeCloudControllerClient) MoveRouteReturns(result1 ccv3.Warnings, result2 error) { + fake.moveRouteMutex.Lock() + defer fake.moveRouteMutex.Unlock() + fake.MoveRouteStub = nil + fake.moveRouteReturns = struct { + result1 ccv3.Warnings + result2 error + }{result1, result2} +} + +func (fake *FakeCloudControllerClient) MoveRouteReturnsOnCall(i int, result1 ccv3.Warnings, result2 error) { + fake.moveRouteMutex.Lock() + defer fake.moveRouteMutex.Unlock() + fake.MoveRouteStub = nil + if fake.moveRouteReturnsOnCall == nil { + fake.moveRouteReturnsOnCall = make(map[int]struct { + result1 ccv3.Warnings + result2 error + }) + } + fake.moveRouteReturnsOnCall[i] = struct { + result1 ccv3.Warnings + result2 error + }{result1, result2} +} + func (fake *FakeCloudControllerClient) PollJob(arg1 ccv3.JobURL) (ccv3.Warnings, error) { fake.pollJobMutex.Lock() ret, specificReturn := fake.pollJobReturnsOnCall[len(fake.pollJobArgsForCall)] @@ -14721,6 +14799,8 @@ func (fake *FakeCloudControllerClient) Invocations() map[string][][]interface{} defer fake.makeRequestSendReceiveRawMutex.RUnlock() fake.mapRouteMutex.RLock() defer fake.mapRouteMutex.RUnlock() + fake.moveRouteMutex.RLock() + defer fake.moveRouteMutex.RUnlock() fake.pollJobMutex.RLock() defer fake.pollJobMutex.RUnlock() fake.pollJobForStateMutex.RLock() diff --git a/actor/v7pushaction/handle_app_path_override_test.go b/actor/v7pushaction/handle_app_path_override_test.go index 60376947d79..b77a6d521dd 100644 --- a/actor/v7pushaction/handle_app_path_override_test.go +++ b/actor/v7pushaction/handle_app_path_override_test.go @@ -4,6 +4,7 @@ import ( "io/ioutil" "os" "path/filepath" + "runtime" . "code.cloudfoundry.org/cli/actor/v7pushaction" "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers" @@ -94,7 +95,11 @@ var _ = Describe("HandleAppPathOverride", func() { absoluteAppFilehandle, err = ioutil.TempFile("", "") Expect(err).NotTo(HaveOccurred()) defer absoluteAppFilehandle.Close() - relativeAppFilePath = filepath.Join(".", absoluteAppFilehandle.Name()) + if runtime.GOOS == "windows" { + relativeAppFilePath = absoluteAppFilehandle.Name() + } else { + relativeAppFilePath = filepath.Join(filepath.Dir("/"), absoluteAppFilehandle.Name()) + } flagOverrides.ProvidedAppPath = relativeAppFilePath // TODO: Do NOT use Chdir! it affects ALL other threads diff --git a/api/cloudcontroller/ccv3/internal/api_routes.go b/api/cloudcontroller/ccv3/internal/api_routes.go index 7029d8073fa..5da806e7d29 100644 --- a/api/cloudcontroller/ccv3/internal/api_routes.go +++ b/api/cloudcontroller/ccv3/internal/api_routes.go @@ -130,6 +130,7 @@ const ( PatchSpaceFeaturesRequest = "PatchSpaceFeatures" PatchSpaceQuotaRequest = "PatchSpaceQuota" PatchStackRequest = "PatchStack" + PatchMoveRouteRequest = "PatchMoveRouteRequest" PostApplicationActionApplyManifest = "PostApplicationActionApplyM" PostApplicationActionRestartRequest = "PostApplicationActionRestart" PostApplicationActionStartRequest = "PostApplicationActionStart" @@ -279,6 +280,7 @@ var APIRoutes = map[string]Route{ UnmapRouteRequest: {Path: "/v3/routes/:route_guid/destinations/:destination_guid", Method: http.MethodDelete}, PatchDestinationRequest: {Path: "/v3/routes/:route_guid/destinations/:destination_guid", Method: http.MethodPatch}, ShareRouteRequest: {Path: "/v3/routes/:route_guid/relationships/shared_spaces", Method: http.MethodPost}, + PatchMoveRouteRequest: {Path: "/v3/routes/:route_guid/relationships/space", Method: http.MethodPatch}, GetSecurityGroupsRequest: {Path: "/v3/security_groups", Method: http.MethodGet}, PostSecurityGroupRequest: {Path: "/v3/security_groups", Method: http.MethodPost}, DeleteSecurityGroupRequest: {Path: "/v3/security_groups/:security_group_guid", Method: http.MethodDelete}, diff --git a/api/cloudcontroller/ccv3/route.go b/api/cloudcontroller/ccv3/route.go index d7ad9a2c182..56f068640a6 100644 --- a/api/cloudcontroller/ccv3/route.go +++ b/api/cloudcontroller/ccv3/route.go @@ -173,3 +173,28 @@ func (client Client) ShareRoute(routeGUID string, spaceGUID string) (Warnings, e }) return warnings, err } + +func (client Client) MoveRoute(routeGUID string, spaceGUID string) (Warnings, error) { + type space struct { + GUID string `json:"guid"` + } + + type body struct { + Data space `json:"data"` + } + + requestBody := body{ + Data: space{ + GUID: spaceGUID, + }, + } + + var responseBody resources.Build + _, warnings, err := client.MakeRequest(RequestParams{ + RequestName: internal.PatchMoveRouteRequest, + URIParams: internal.Params{"route_guid": routeGUID}, + RequestBody: &requestBody, + ResponseBody: &responseBody, + }) + return warnings, err +} diff --git a/command/common/command_list_v7.go b/command/common/command_list_v7.go index fada59bcb02..588e47e391f 100644 --- a/command/common/command_list_v7.go +++ b/command/common/command_list_v7.go @@ -173,6 +173,7 @@ type commandList struct { Target v7.TargetCommand `command:"target" alias:"t" description:"Set or view the targeted org or space"` Tasks v7.TasksCommand `command:"tasks" description:"List tasks of an app"` TerminateTask v7.TerminateTaskCommand `command:"terminate-task" description:"Terminate a running task of an app"` + MoveRoute v7.MoveRouteCommand `command:"move-route" description:"Assign a route to a different space"` UnbindRouteService v7.UnbindRouteServiceCommand `command:"unbind-route-service" alias:"urs" description:"Unbind a service instance from an HTTP route"` UnbindRunningSecurityGroup v7.UnbindRunningSecurityGroupCommand `command:"unbind-running-security-group" description:"Unbind a security group from the set of security groups for running applications globally"` UnbindSecurityGroup v7.UnbindSecurityGroupCommand `command:"unbind-security-group" description:"Unbind a security group from a space"` diff --git a/command/common/internal/help_all_display.go b/command/common/internal/help_all_display.go index 8c6e9957f09..97990a5002d 100644 --- a/command/common/internal/help_all_display.go +++ b/command/common/internal/help_all_display.go @@ -69,6 +69,7 @@ var HelpCategoryList = []HelpCategory{ {"delete-orphaned-routes"}, {"update-destination"}, {"share-route"}, + {"move-route"}, }, }, { diff --git a/command/v7/actor.go b/command/v7/actor.go index 64ef63dd1f0..3bbae507c69 100644 --- a/command/v7/actor.go +++ b/command/v7/actor.go @@ -183,6 +183,7 @@ type Actor interface { MakeCurlRequest(httpMethod string, path string, customHeaders []string, httpData string, failOnHTTPError bool) ([]byte, *http.Response, error) MapRoute(routeGUID string, appGUID string, destinationProtocol string) (v7action.Warnings, error) Marketplace(filter v7action.MarketplaceFilter) ([]v7action.ServiceOfferingWithPlans, v7action.Warnings, error) + MoveRoute(routeGUID string, spaceGUID string) (v7action.Warnings, error) ParseAccessToken(accessToken string) (jwt.JWT, error) PollBuild(buildGUID string, appName string) (resources.Droplet, v7action.Warnings, error) PollPackage(pkg resources.Package) (resources.Package, v7action.Warnings, error) diff --git a/command/v7/move_route_command.go b/command/v7/move_route_command.go new file mode 100644 index 00000000000..4ba150568d1 --- /dev/null +++ b/command/v7/move_route_command.go @@ -0,0 +1,101 @@ +package v7 + +import ( + "code.cloudfoundry.org/cli/actor/actionerror" + "code.cloudfoundry.org/cli/command/flag" +) + +type MoveRouteCommand struct { + BaseCommand + + RequireArgs flag.Domain `positional-args:"yes"` + Hostname string `long:"hostname" short:"n" description:"Hostname for the HTTP route (required for shared domains)"` + Path flag.V7RoutePath `long:"path" description:"Path for the HTTP route"` + DestinationOrg string `short:"o" description:"The org of the destination app (Default: targeted org)"` + DestinationSpace string `short:"s" description:"The space of the destination app (Default: targeted space)"` + + relatedCommands interface{} `related_commands:"create-route, map-route, unmap-route, routes"` +} + +func (cmd MoveRouteCommand) Usage() string { + return ` + Transfers the ownership of a route to a another space: + CF_NAME move-route DOMAIN [--hostname HOSTNAME] [--path PATH] -s OTHER_SPACE [-o OTHER_ORG]` +} + +func (cmd MoveRouteCommand) Examples() string { + return ` + CF_NAME move-route example.com --hostname myHost --path foo -s TargetSpace -o TargetOrg # myhost.example.com/foo + CF_NAME move-route example.com --hostname myHost -s TargetSpace # myhost.example.com + CF_NAME move-route example.com --hostname myHost -s TargetSpace -o TargetOrg # myhost.example.com` +} + +func (cmd MoveRouteCommand) Execute(args []string) error { + err := cmd.SharedActor.CheckTarget(true, true) + if err != nil { + return err + } + + user, err := cmd.Actor.GetCurrentUser() + if err != nil { + return err + } + + domain, warnings, err := cmd.Actor.GetDomainByName(cmd.RequireArgs.Domain) + cmd.UI.DisplayWarnings(warnings) + if err != nil { + return err + } + + path := cmd.Path.Path + route, warnings, err := cmd.Actor.GetRouteByAttributes(domain, cmd.Hostname, path, 0) + cmd.UI.DisplayWarnings(warnings) + if err != nil { + if _, ok := err.(actionerror.RouteNotFoundError); ok { + cmd.UI.DisplayText("Can not transfer ownership of route:") + return err + } + } + + destinationOrgName := cmd.DestinationOrg + + if destinationOrgName == "" { + destinationOrgName = cmd.Config.TargetedOrganizationName() + } + + destinationOrg, warnings, err := cmd.Actor.GetOrganizationByName(destinationOrgName) + + if err != nil { + if _, ok := err.(actionerror.OrganizationNotFoundError); ok { + cmd.UI.DisplayText("Can not transfer ownership of route:") + return err + } + } + + targetedSpace, warnings, err := cmd.Actor.GetSpaceByNameAndOrganization(cmd.DestinationSpace, destinationOrg.GUID) + if err != nil { + if _, ok := err.(actionerror.SpaceNotFoundError); ok { + cmd.UI.DisplayText("Can not transfer ownership of route:") + return err + } + } + + url := desiredURL(domain.Name, cmd.Hostname, path, 0) + cmd.UI.DisplayTextWithFlavor("Move ownership of route {{.URL}} to space {{.DestinationSpace}} as {{.User}}", + map[string]interface{}{ + "URL": url, + "DestinationSpace": cmd.DestinationSpace, + "User": user.Name, + }) + warnings, err = cmd.Actor.MoveRoute( + route.GUID, + targetedSpace.GUID, + ) + cmd.UI.DisplayWarnings(warnings) + if err != nil { + return err + } + cmd.UI.DisplayOK() + + return nil +} diff --git a/command/v7/move_route_command_test.go b/command/v7/move_route_command_test.go new file mode 100644 index 00000000000..4ff7b7360bd --- /dev/null +++ b/command/v7/move_route_command_test.go @@ -0,0 +1,279 @@ +package v7_test + +import ( + "code.cloudfoundry.org/cli/actor/actionerror" + "code.cloudfoundry.org/cli/actor/v7action" + "code.cloudfoundry.org/cli/cf/errors" + "code.cloudfoundry.org/cli/command/commandfakes" + "code.cloudfoundry.org/cli/command/flag" + v7 "code.cloudfoundry.org/cli/command/v7" + "code.cloudfoundry.org/cli/command/v7/v7fakes" + "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/configv3" + "code.cloudfoundry.org/cli/util/ui" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gbytes" +) + +var _ = Describe("move-route Command", func() { + var ( + cmd v7.MoveRouteCommand + testUI *ui.UI + fakeConfig *commandfakes.FakeConfig + fakeSharedActor *commandfakes.FakeSharedActor + fakeActor *v7fakes.FakeActor + binaryName string + executeErr error + domainName string + orgName string + spaceName string + hostname string + path string + ) + + BeforeEach(func() { + testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) + fakeConfig = new(commandfakes.FakeConfig) + fakeSharedActor = new(commandfakes.FakeSharedActor) + fakeActor = new(v7fakes.FakeActor) + + binaryName = "myBinaryBread" + fakeConfig.BinaryNameReturns(binaryName) + + domainName = "some-domain.com" + orgName = "org-name-a" + spaceName = "space-name-a" + hostname = "myHostname" + path = "myPath" + + cmd = v7.MoveRouteCommand{ + BaseCommand: v7.BaseCommand{ + UI: testUI, + Config: fakeConfig, + SharedActor: fakeSharedActor, + Actor: fakeActor, + }, + RequireArgs: flag.Domain{Domain: domainName}, + Hostname: hostname, + Path: flag.V7RoutePath{Path: path}, + DestinationOrg: orgName, + DestinationSpace: spaceName, + } + + fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "some-space", GUID: "some-space-guid"}) + fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org"}) + fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + }) + + JustBeforeEach(func() { + executeErr = cmd.Execute(nil) + }) + + It("checks that target", func() { + Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) + checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) + Expect(checkTargetedOrg).To(BeTrue()) + Expect(checkTargetedSpace).To(BeTrue()) + }) + + When("checking target fails", func() { + BeforeEach(func() { + fakeSharedActor.CheckTargetReturns(actionerror.NoOrganizationTargetedError{BinaryName: binaryName}) + }) + It("returns an error", func() { + Expect(executeErr).To(MatchError(actionerror.NoOrganizationTargetedError{BinaryName: binaryName})) + + Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) + checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) + Expect(checkTargetedOrg).To(BeTrue()) + Expect(checkTargetedSpace).To(BeTrue()) + }) + }) + + When("the user is not logged in", func() { + var expectedErr error + + BeforeEach(func() { + expectedErr = errors.New("some current user error") + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) + }) + + It("return an error", func() { + Expect(executeErr).To(Equal(expectedErr)) + }) + }) + + When("the user is logged in and targeted", func() { + When("getting the domain errors", func() { + BeforeEach(func() { + fakeActor.GetDomainByNameReturns(resources.Domain{}, v7action.Warnings{"get-domain-warnings"}, errors.New("get-domain-error")) + }) + + It("returns the error and displays warnings", func() { + Expect(testUI.Err).To(Say("get-domain-warnings")) + Expect(executeErr).To(MatchError(errors.New("get-domain-error"))) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(0)) + + Expect(fakeActor.GetSpaceByNameAndOrganizationCallCount()).To(Equal(0)) + + Expect(fakeActor.MoveRouteCallCount()).To(Equal(0)) + }) + }) + + When("getting the domain succeeds", func() { + BeforeEach(func() { + fakeActor.GetDomainByNameReturns( + resources.Domain{Name: domainName, GUID: "domain-guid"}, + v7action.Warnings{"get-domain-warnings"}, + nil, + ) + }) + + When("the requested route does not exist", func() { + BeforeEach(func() { + fakeActor.GetRouteByAttributesReturns( + resources.Route{}, + v7action.Warnings{"get-route-warnings"}, + actionerror.RouteNotFoundError{}, + ) + }) + + It("displays error message", func() { + Expect(testUI.Err).To(Say("get-domain-warnings")) + Expect(testUI.Err).To(Say("get-route-warnings")) + Expect(executeErr).To(HaveOccurred()) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + }) + }) + + When("the requested route exists", func() { + BeforeEach(func() { + fakeActor.GetRouteByAttributesReturns( + resources.Route{GUID: "route-guid"}, + v7action.Warnings{"get-route-warnings"}, + nil, + ) + }) + When("getting the target space errors", func() { + BeforeEach(func() { + fakeActor.GetOrganizationByNameReturns( + resources.Organization{GUID: "org-guid-a"}, + v7action.Warnings{"get-route-warnings"}, + nil, + ) + fakeActor.GetSpaceByNameAndOrganizationReturns( + resources.Space{}, + v7action.Warnings{"get-route-warnings"}, + actionerror.SpaceNotFoundError{}, + ) + }) + It("returns the error and warnings", func() { + Expect(executeErr).To(HaveOccurred()) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + + Expect(fakeActor.GetOrganizationByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetOrganizationByNameArgsForCall(0)).To(Equal(orgName)) + Expect(fakeActor.GetSpaceByNameAndOrganizationCallCount()).To(Equal(1)) + spaceName, orgGuid := fakeActor.GetSpaceByNameAndOrganizationArgsForCall(0) + Expect(spaceName).To(Equal("space-name-a")) + Expect(orgGuid).To(Equal("org-guid-a")) + + Expect(fakeActor.MoveRouteCallCount()).To(Equal(0)) + }) + }) + When("getting the target org errors", func() { + BeforeEach(func() { + fakeActor.GetOrganizationByNameReturns( + resources.Organization{}, + v7action.Warnings{"get-route-warnings"}, + actionerror.OrganizationNotFoundError{}, + ) + }) + It("returns the error and warnings", func() { + Expect(executeErr).To(HaveOccurred()) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + + Expect(fakeActor.GetOrganizationByNameCallCount()).To(Equal(1)) + orgName := fakeActor.GetOrganizationByNameArgsForCall(0) + Expect(orgName).To(Equal("org-name-a")) + + Expect(fakeActor.MoveRouteCallCount()).To(Equal(0)) + }) + }) + When("getting the target space succeeds", func() { + BeforeEach(func() { + fakeActor.GetOrganizationByNameReturns( + resources.Organization{GUID: "org-guid-a"}, + v7action.Warnings{"get-route-warnings"}, + nil, + ) + fakeActor.GetSpaceByNameAndOrganizationReturns( + resources.Space{GUID: "space-guid-b"}, + v7action.Warnings{"get-route-warnings"}, + nil, + ) + }) + It("exits 0 with helpful message that the route is now transferred", func() { + Expect(executeErr).ShouldNot(HaveOccurred()) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + + Expect(fakeActor.GetOrganizationByNameCallCount()).To(Equal(1)) + orgName := fakeActor.GetOrganizationByNameArgsForCall(0) + Expect(orgName).To(Equal("org-name-a")) + + Expect(fakeActor.GetSpaceByNameAndOrganizationCallCount()).To(Equal(1)) + spaceName, orgGuid := fakeActor.GetSpaceByNameAndOrganizationArgsForCall(0) + Expect(spaceName).To(Equal("space-name-a")) + Expect(orgGuid).To(Equal("org-guid-a")) + Expect(fakeActor.MoveRouteCallCount()).To(Equal(1)) + }) + }) + }) + }) + }) +}) diff --git a/command/v7/v7fakes/fake_actor.go b/command/v7/v7fakes/fake_actor.go index 1a950e4692e..f3cddabd4f7 100644 --- a/command/v7/v7fakes/fake_actor.go +++ b/command/v7/v7fakes/fake_actor.go @@ -2489,6 +2489,20 @@ type FakeActor struct { result2 v7action.Warnings result3 error } + MoveRouteStub func(string, string) (v7action.Warnings, error) + moveRouteMutex sync.RWMutex + moveRouteArgsForCall []struct { + arg1 string + arg2 string + } + moveRouteReturns struct { + result1 v7action.Warnings + result2 error + } + moveRouteReturnsOnCall map[int]struct { + result1 v7action.Warnings + result2 error + } ParseAccessTokenStub func(string) (jwt.JWT, error) parseAccessTokenMutex sync.RWMutex parseAccessTokenArgsForCall []struct { @@ -14180,6 +14194,70 @@ func (fake *FakeActor) MarketplaceReturnsOnCall(i int, result1 []v7action.Servic }{result1, result2, result3} } +func (fake *FakeActor) MoveRoute(arg1 string, arg2 string) (v7action.Warnings, error) { + fake.moveRouteMutex.Lock() + ret, specificReturn := fake.moveRouteReturnsOnCall[len(fake.moveRouteArgsForCall)] + fake.moveRouteArgsForCall = append(fake.moveRouteArgsForCall, struct { + arg1 string + arg2 string + }{arg1, arg2}) + fake.recordInvocation("MoveRoute", []interface{}{arg1, arg2}) + fake.moveRouteMutex.Unlock() + if fake.MoveRouteStub != nil { + return fake.MoveRouteStub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.moveRouteReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeActor) MoveRouteCallCount() int { + fake.moveRouteMutex.RLock() + defer fake.moveRouteMutex.RUnlock() + return len(fake.moveRouteArgsForCall) +} + +func (fake *FakeActor) MoveRouteCalls(stub func(string, string) (v7action.Warnings, error)) { + fake.moveRouteMutex.Lock() + defer fake.moveRouteMutex.Unlock() + fake.MoveRouteStub = stub +} + +func (fake *FakeActor) MoveRouteArgsForCall(i int) (string, string) { + fake.moveRouteMutex.RLock() + defer fake.moveRouteMutex.RUnlock() + argsForCall := fake.moveRouteArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeActor) MoveRouteReturns(result1 v7action.Warnings, result2 error) { + fake.moveRouteMutex.Lock() + defer fake.moveRouteMutex.Unlock() + fake.MoveRouteStub = nil + fake.moveRouteReturns = struct { + result1 v7action.Warnings + result2 error + }{result1, result2} +} + +func (fake *FakeActor) MoveRouteReturnsOnCall(i int, result1 v7action.Warnings, result2 error) { + fake.moveRouteMutex.Lock() + defer fake.moveRouteMutex.Unlock() + fake.MoveRouteStub = nil + if fake.moveRouteReturnsOnCall == nil { + fake.moveRouteReturnsOnCall = make(map[int]struct { + result1 v7action.Warnings + result2 error + }) + } + fake.moveRouteReturnsOnCall[i] = struct { + result1 v7action.Warnings + result2 error + }{result1, result2} +} + func (fake *FakeActor) ParseAccessToken(arg1 string) (jwt.JWT, error) { fake.parseAccessTokenMutex.Lock() ret, specificReturn := fake.parseAccessTokenReturnsOnCall[len(fake.parseAccessTokenArgsForCall)] @@ -19326,6 +19404,8 @@ func (fake *FakeActor) Invocations() map[string][][]interface{} { defer fake.mapRouteMutex.RUnlock() fake.marketplaceMutex.RLock() defer fake.marketplaceMutex.RUnlock() + fake.moveRouteMutex.RLock() + defer fake.moveRouteMutex.RUnlock() fake.parseAccessTokenMutex.RLock() defer fake.parseAccessTokenMutex.RUnlock() fake.pollBuildMutex.RLock() diff --git a/integration/v7/isolated/move_route_command_test.go b/integration/v7/isolated/move_route_command_test.go new file mode 100644 index 00000000000..b973fb1d007 --- /dev/null +++ b/integration/v7/isolated/move_route_command_test.go @@ -0,0 +1,204 @@ +package isolated + +import ( + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" + . "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers" + "code.cloudfoundry.org/cli/integration/helpers" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gbytes" + . "github.com/onsi/gomega/gexec" +) + +var _ = Describe("move route command", func() { + Context("Help", func() { + It("appears in cf help -a", func() { + session := helpers.CF("help", "-a") + + Eventually(session).Should(Exit(0)) + Expect(session).To(HaveCommandInCategoryWithDescription("move-route", "ROUTES", "Assign a route to a different space")) + }) + + It("displays the help information", func() { + session := helpers.CF("move-route", "--help") + Eventually(session).Should(Say(`NAME:`)) + Eventually(session).Should(Say("move-route - Assign a route to a different space")) + Eventually(session).Should(Say(`\n`)) + + Eventually(session).Should(Say(`USAGE:`)) + Eventually(session).Should(Say(`Transfers the ownership of a route to a another space:`)) + Eventually(session).Should(Say(`cf move-route DOMAIN \[--hostname HOSTNAME\] \[--path PATH\] -s OTHER_SPACE \[-o OTHER_ORG\]`)) + Eventually(session).Should(Say(`\n`)) + + Eventually(session).Should(Say(`EXAMPLES:`)) + Eventually(session).Should(Say(`cf move-route example.com --hostname myHost --path foo -s TargetSpace -o TargetOrg # myhost.example.com/foo`)) + Eventually(session).Should(Say(`cf move-route example.com --hostname myHost -s TargetSpace # myhost.example.com`)) + Eventually(session).Should(Say(`cf move-route example.com --hostname myHost -s TargetSpace -o TargetOrg # myhost.example.com`)) + Eventually(session).Should(Say(`\n`)) + + Eventually(session).Should(Say(`OPTIONS:`)) + Eventually(session).Should(Say(`--hostname, -n\s+Hostname for the HTTP route \(required for shared domains\)`)) + Eventually(session).Should(Say(`--path\s+Path for the HTTP route`)) + Eventually(session).Should(Say(`-o\s+The org of the destination app \(Default: targeted org\)`)) + Eventually(session).Should(Say(`-s\s+The space of the destination app \(Default: targeted space\)`)) + Eventually(session).Should(Say(`\n`)) + + Eventually(session).Should(Say(`SEE ALSO:`)) + Eventually(session).Should(Say(`create-route, map-route, routes, unmap-route`)) + + Eventually(session).Should(Exit(0)) + }) + }) + + When("the environment is not setup correctly", func() { + It("fails with the appropriate errors", func() { + helpers.CheckEnvironmentTargetedCorrectly(true, false, ReadOnlyOrg, "move-route", "some-domain", "-s SOME_SPACE") + }) + }) + + When("the environment is set up correctly", func() { + var ( + userName string + orgName string + spaceName string + ) + + BeforeEach(func() { + helpers.SkipIfVersionLessThan(ccversion.MinVersionHTTP2RoutingV3) + orgName = helpers.NewOrgName() + spaceName = helpers.NewSpaceName() + + helpers.SetupCF(orgName, spaceName) + userName, _ = helpers.GetCredentials() + }) + + AfterEach(func() { + helpers.QuickDeleteOrg(orgName) + }) + + When("the domain exists", func() { + var ( + domainName string + targetSpaceName string + ) + + BeforeEach(func() { + domainName = helpers.NewDomainName() + }) + + When("the route exists", func() { + var ( + domain helpers.Domain + hostname string + ) + When("the target space exists in targeted org", func() { + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "panera-bread" + targetSpaceName = helpers.NewSpaceName() + helpers.CreateSpace(targetSpaceName) + domain.CreateShared() + Eventually(helpers.CF("create-route", domain.Name, "--hostname", hostname)).Should(Exit(0)) + }) + + AfterEach(func() { + domain.DeleteShared() + }) + + It("transfers the route to the destination space", func() { + session := helpers.CF("move-route", domainName, "--hostname", hostname, "-s", targetSpaceName) + Eventually(session).Should(Say(`Move ownership of route %s.%s to space %s as %s`, hostname, domainName, targetSpaceName, userName)) + Eventually(session).Should(Say(`OK`)) + Eventually(session).Should(Exit(0)) + }) + }) + + When("the target organization does not exist", func() { + var targetOrgName string + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "panera-bread" + targetSpaceName = helpers.NewSpaceName() + targetOrgName = helpers.NewOrgName() + domain.CreateShared() + Eventually(helpers.CF("create-route", domain.Name, "--hostname", hostname)).Should(Exit(0)) + }) + + It("exists with 1 and an error message", func() { + session := helpers.CF("move-route", domainName, "--hostname", hostname, "-o", targetOrgName, "-s", targetSpaceName) + Eventually(session).Should(Say("Can not transfer ownership of route:")) + Eventually(session).Should(Say(`FAILED`)) + Eventually(session).Should(Exit(1)) + }) + }) + + When("the target space exists in another existing org", func() { + var targetOrgName string + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "menchies-icecream" + targetOrgName = helpers.NewOrgName() + targetSpaceName = helpers.NewSpaceName() + helpers.CreateOrgAndSpace(targetOrgName, targetSpaceName) + helpers.SetupCF(orgName, spaceName) + domain.CreateShared() + Eventually(helpers.CF("create-route", domain.Name, "--hostname", hostname)).Should(Exit(0)) + }) + + AfterEach(func() { + domain.DeleteShared() + }) + + It("Transfers ownership of the route to the destination space", func() { + session := helpers.CF("move-route", domainName, "--hostname", hostname, "-o", targetOrgName, "-s", targetSpaceName) + Eventually(session).Should(Say(`Move ownership of route %s.%s to space %s as %s`, hostname, domainName, targetSpaceName, userName)) + Eventually(session).Should(Say(`OK`)) + Eventually(session).Should(Exit(0)) + }) + }) + + When("the space does not exist", func() { + var destinationSpaceName string + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "menchies-icecream" + destinationSpaceName = "doesNotExistSpace" + domain.CreateShared() + Eventually(helpers.CF("create-route", domain.Name, "--hostname", hostname)).Should(Exit(0)) + }) + + It("exists with 1 with an error", func() { + session := helpers.CF("move-route", domainName, "--hostname", hostname, "-s", destinationSpaceName) + Eventually(session).Should(Say("Can not transfer ownership of route:")) + Eventually(session).Should(Say(`FAILED`)) + Eventually(session).Should(Exit(1)) + }) + }) + }) + + When("the route does not exist", func() { + var ( + domain helpers.Domain + hostname string + ) + + When("the target space exists", func() { + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "panera-bread" + targetSpaceName = helpers.NewSpaceName() + helpers.CreateSpace(targetSpaceName) + domain.CreateShared() + }) + + It("exits with 1 with an error message", func() { + session := helpers.CF("move-route", domainName, "--hostname", hostname, "-s", targetSpaceName) + Eventually(session).Should(Say("Can not transfer ownership of route:")) + Eventually(session).Should(Say(`FAILED`)) + Eventually(session).Should(Exit(1)) + }) + }) + }) + }) + }) +}) From 7bac32a4ad165f93b4b6fdca9e9cfd5e125c5385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Diego=20Gonz=C3=A1lez?= <25335192+jdgonzaleza@users.noreply.github.com> Date: Tue, 30 Aug 2022 14:14:45 -0500 Subject: [PATCH 042/248] Adds regex in order to get cf_users number (#2310) Co-authored-by: Juan Diego Gonzalez --- bin/cleanup-integration | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cleanup-integration b/bin/cleanup-integration index bb5592b173d..3dd18f8c022 100755 --- a/bin/cleanup-integration +++ b/bin/cleanup-integration @@ -62,7 +62,7 @@ for stack in $(cf stacks | awk '/INTEGRATION-STACK/ { print $1 }'); do cf curl -X DELETE "/v3/stacks/$(cf stack --guid $stack)" done -CF_USERS=$(cf curl /v3/users | grep total_results | grep -o '[0-9]\+') +CF_USERS=$(cf curl /v3/users | grep -oP '(?<="total_results":)[^"]*' |grep -o '[0-9]\+') USER_PAGES=$(( $CF_USERS / 50 + 1)) for ((i=1; i<=${USER_PAGES}; i++)) ; do From 6715868772c0306d23e5aa9a67a10009af0621dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Diego=20Gonz=C3=A1lez?= <25335192+jdgonzaleza@users.noreply.github.com> Date: Tue, 6 Sep 2022 15:00:25 -0500 Subject: [PATCH 043/248] Integration fixes * Update JSON formatting in test samples Recently CAPI removed JSON pretty formatting in cloudfoundry/cloud_controller_ng#2944 In this commit we enhanced the way of checking for values in json * Adds helpers for testing partial json Co-authored-by: Juan Diego Gonzalez Co-authored-by: Alexander Berez --- integration/helpers/set_env_command.go | 17 +++++++++++++++++ integration/helpers/ssh_command.go | 15 +++++++++++++++ .../v7/isolated/disable_ssh_command_test.go | 13 +++++++++++-- .../v7/isolated/enable_ssh_command_test.go | 12 ++++++++++-- .../v7/isolated/marketplace_command_test.go | 2 +- integration/v7/isolated/set_env_command_test.go | 17 ++++++++++++++--- 6 files changed, 68 insertions(+), 8 deletions(-) create mode 100644 integration/helpers/set_env_command.go create mode 100644 integration/helpers/ssh_command.go diff --git a/integration/helpers/set_env_command.go b/integration/helpers/set_env_command.go new file mode 100644 index 00000000000..23c624cb220 --- /dev/null +++ b/integration/helpers/set_env_command.go @@ -0,0 +1,17 @@ +package helpers + +import ( + "encoding/json" +) + +func GetsDefaultEnvVarValue(stream []byte) string { + envVariableJSON := struct { + Var struct { + SomeEnvVar string `json:"SOME_ENV_VAR"` + } `json:"var"` + }{} + + json.Unmarshal(stream, &envVariableJSON) + + return envVariableJSON.Var.SomeEnvVar +} diff --git a/integration/helpers/ssh_command.go b/integration/helpers/ssh_command.go new file mode 100644 index 00000000000..df9bda85d90 --- /dev/null +++ b/integration/helpers/ssh_command.go @@ -0,0 +1,15 @@ +package helpers + +import ( + "encoding/json" +) + +func GetsEnablementValue(stream []byte) bool { + enablementResponse := struct { + Enabled bool `json:"enabled"` + }{} + + json.Unmarshal(stream, &enablementResponse) + + return enablementResponse.Enabled +} diff --git a/integration/v7/isolated/disable_ssh_command_test.go b/integration/v7/isolated/disable_ssh_command_test.go index ba5563fa693..d68dc0c58da 100644 --- a/integration/v7/isolated/disable_ssh_command_test.go +++ b/integration/v7/isolated/disable_ssh_command_test.go @@ -104,8 +104,13 @@ var _ = Describe("disable-ssh command", func() { Eventually(session).Should(Exit(0)) session = helpers.CF("curl", fmt.Sprintf("v3/apps/%s/ssh_enabled", helpers.AppGUID(appName))) - Eventually(session).Should(Say(`"enabled": %s`, "false")) + Eventually(session).Should(Exit(0)) + + bytes := session.Out.Contents() + + actualEnablementValue := helpers.GetsEnablementValue(bytes) + Expect(actualEnablementValue).To(Equal(false)) }) }) @@ -123,8 +128,12 @@ var _ = Describe("disable-ssh command", func() { Eventually(session).Should(Say("OK")) session = helpers.CF("curl", fmt.Sprintf("v3/apps/%s/ssh_enabled", helpers.AppGUID(appName))) - Eventually(session).Should(Say(`"enabled": %s`, "false")) Eventually(session).Should(Exit(0)) + + bytes := session.Out.Contents() + + actualEnablementValue := helpers.GetsEnablementValue(bytes) + Expect(actualEnablementValue).To(Equal(false)) }) }) }) diff --git a/integration/v7/isolated/enable_ssh_command_test.go b/integration/v7/isolated/enable_ssh_command_test.go index cfaa89bb3dc..460bc6fbf9c 100644 --- a/integration/v7/isolated/enable_ssh_command_test.go +++ b/integration/v7/isolated/enable_ssh_command_test.go @@ -104,8 +104,12 @@ var _ = Describe("enable-ssh command", func() { Eventually(session).Should(Exit(0)) session = helpers.CF("curl", fmt.Sprintf("v3/apps/%s/ssh_enabled", helpers.AppGUID(appName))) - Eventually(session).Should(Say(`"enabled": %s`, "true")) Eventually(session).Should(Exit(0)) + + bytes := session.Out.Contents() + + actualEnablementValue := helpers.GetsEnablementValue(bytes) + Expect(actualEnablementValue).To(Equal(true)) }) }) @@ -123,8 +127,12 @@ var _ = Describe("enable-ssh command", func() { Eventually(session).Should(Say("OK")) session = helpers.CF("curl", fmt.Sprintf("v3/apps/%s/ssh_enabled", helpers.AppGUID(appName))) - Eventually(session).Should(Say(`"enabled": %s`, "true")) Eventually(session).Should(Exit(0)) + + bytes := session.Out.Contents() + + actualEnablementValue := helpers.GetsEnablementValue(bytes) + Expect(actualEnablementValue).To(Equal(true)) }) }) diff --git a/integration/v7/isolated/marketplace_command_test.go b/integration/v7/isolated/marketplace_command_test.go index 288a59e9f2f..86ae14f4412 100644 --- a/integration/v7/isolated/marketplace_command_test.go +++ b/integration/v7/isolated/marketplace_command_test.go @@ -140,7 +140,7 @@ var _ = Describe("marketplace command", func() { Unit: "MONTHLY", }, { - Amount: map[string]float64{"usd": 0.999}, + Amount: map[string]float64{"usd": 1.00}, Unit: "1GB of messages over 20GB", }, } diff --git a/integration/v7/isolated/set_env_command_test.go b/integration/v7/isolated/set_env_command_test.go index fd5afe6a35c..2f2c29d1fca 100644 --- a/integration/v7/isolated/set_env_command_test.go +++ b/integration/v7/isolated/set_env_command_test.go @@ -130,8 +130,12 @@ var _ = Describe("set-env command", func() { Eventually(session).Should(Exit(0)) session = helpers.CF("curl", fmt.Sprintf("v3/apps/%s/environment_variables", helpers.AppGUID(appName))) - Eventually(session).Should(Say(`"%s": "%s"`, envVarName, envVarValue)) Eventually(session).Should(Exit(0)) + + bytes := session.Out.Contents() + + actualEnvVarValue := helpers.GetsDefaultEnvVarValue(bytes) + Expect(actualEnvVarValue).To(Equal(envVarValue)) }) // This is to prevent the '-' being read in as another flag @@ -149,8 +153,12 @@ var _ = Describe("set-env command", func() { Eventually(session).Should(Exit(0)) session = helpers.CF("curl", fmt.Sprintf("v3/apps/%s/environment_variables", helpers.AppGUID(appName))) - Eventually(session).Should(Say(`"%s": "%s"`, envVarName, envVarValue)) Eventually(session).Should(Exit(0)) + + bytes := session.Out.Contents() + + actualEnvVarValue := helpers.GetsDefaultEnvVarValue(bytes) + Expect(actualEnvVarValue).To(Equal(envVarValue)) }) }) }) @@ -170,8 +178,11 @@ var _ = Describe("set-env command", func() { Eventually(session).Should(Exit(0)) session = helpers.CF("curl", fmt.Sprintf("v3/apps/%s/environment_variables", helpers.AppGUID(appName))) - Eventually(session).Should(Say(`"%s": "%s"`, envVarName, someOtherValue)) Eventually(session).Should(Exit(0)) + bytes := session.Out.Contents() + + actualEnvVarValue := helpers.GetsDefaultEnvVarValue(bytes) + Expect(actualEnvVarValue).To(Equal(someOtherValue)) }) }) From 94619ee4af79d8c3304389e4b3916d29ee72bbfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Diego=20Gonz=C3=A1lez?= <25335192+jdgonzaleza@users.noreply.github.com> Date: Thu, 8 Sep 2022 12:55:09 -0500 Subject: [PATCH 044/248] logging rate limits flag introduction (#2313) * Feat: create and update org quotas with log volume (#2298) * Show org and space quotas (#2299) * org-quota and space-quota now show log volume * code currently assumes responses with log limits. Consider backward compatibility before shipping. * add log volume to space-quotas and org-quotas commands * will show "unlimited" for old CC API's which is technically correct * Fix unit tests in ccv3 * Create and update space quotas (#2300) * create-space-quota accepts log volume flag * update-space-quota accepts log volume flag * Update create-space-quota flag description * Make it clear that the log volume measured is in bytes rather than log lines. * Push and scale app and run-task * Bump rack from 2.2.3 to 2.2.3.1 in /fixtures/applications/example-app * `cf push` command accepts log rate limit flag * since `cf push` uses manifests this commit also adds support for log rate limit in manifests * `cf scale` command accepts log rate limit flag * app summary displayer can now handle rendering log rate and log rate limit metrics for running instances * app summaries will show `0 of 0` if the cloud controller does not support log rate limit container metrics * `cf run-task` command accepts log rate limit flag * update help text to suggest using ='s with -1 to avoid flag parsing problem * Flag parser accepts 0B, -1B, 0T, etc for flags * this affects non-manifest based commands * Extract constants for instance stats columns * Extract constant for column count Co-authored-by: Carson Long Co-authored-by: Matthew Kocher Co-authored-by: Rebecca Roberts Co-authored-by: Benjamin Fuller --- actor/v7action/organization_quota.go | 3 + actor/v7action/organization_quota_test.go | 16 +- actor/v7action/space_quota.go | 2 + actor/v7action/space_quota_test.go | 11 ++ actor/v7pushaction/actor.go | 1 + .../handle_log_rate_limit_override.go | 24 +++ .../handle_log_rate_limit_override_test.go | 149 +++++++++++++++++ actor/v7pushaction/handle_memory_override.go | 1 - actor/v7pushaction/push_plan.go | 1 + .../ccv3/organization_quota_test.go | 39 +++-- api/cloudcontroller/ccv3/process_instance.go | 16 +- .../ccv3/process_instance_test.go | 12 +- api/cloudcontroller/ccv3/process_test.go | 41 +++-- api/cloudcontroller/ccv3/space_quota_test.go | 54 +++++-- .../ccversion/minimum_version.go | 2 + command/common/command_list_v7.go | 2 +- command/flag/bytes_with_unlimited.go | 59 +++++++ command/flag/bytes_with_unlimited_test.go | 148 +++++++++++++++++ ...limited.go => megabytes_with_unlimited.go} | 6 +- ...st.go => megabytes_with_unlimited_test.go} | 50 +++--- command/v7/create_org_quota_command.go | 33 ++-- command/v7/create_org_quota_command_test.go | 9 +- command/v7/create_space_quota_command.go | 23 +-- command/v7/create_space_quota_command_test.go | 6 +- command/v7/org_quota_command_test.go | 2 + command/v7/org_quotas_command_test.go | 11 +- command/v7/push_command.go | 4 +- command/v7/push_command_test.go | 4 +- command/v7/run_task_command.go | 20 ++- command/v7/run_task_command_test.go | 43 +++++ command/v7/scale_command.go | 33 ++-- command/v7/scale_command_test.go | 150 +++++++++++++----- command/v7/shared/app_summary_displayer.go | 13 ++ .../v7/shared/app_summary_displayer_test.go | 137 +++++++++++----- command/v7/shared/quota_displayer.go | 20 ++- command/v7/space_quota_command_test.go | 2 + command/v7/space_quotas_command_test.go | 10 +- command/v7/update_org_quota_command.go | 27 ++-- command/v7/update_org_quota_command_test.go | 12 +- command/v7/update_space_quota_command.go | 27 ++-- command/v7/update_space_quota_command_test.go | 12 +- integration/helpers/app.go | 14 ++ integration/helpers/app_instance_table.go | 8 +- .../helpers/app_instance_table_test.go | 42 ++--- .../v7/global/org_quota_command_test.go | 1 + .../v7/global/org_quotas_command_test.go | 4 +- integration/v7/isolated/app_command_test.go | 2 +- .../isolated/create_org_quota_command_test.go | 53 ++++++- .../create_space_quota_command_test.go | 23 ++- .../v7/isolated/restart_command_test.go | 26 +-- .../v7/isolated/run_task_command_test.go | 30 +++- integration/v7/isolated/scale_command_test.go | 41 ++++- .../v7/isolated/space_quota_command_test.go | 1 + .../v7/isolated/space_quotas_command_test.go | 4 +- integration/v7/isolated/start_command_test.go | 4 +- .../isolated/update_org_quota_command_test.go | 22 ++- .../update_space_quota_command_test.go | 23 ++- .../combination_manifest_and_flag_test.go | 1 + integration/v7/push/help_test.go | 7 +- .../v7/push/log_rate_limit_flag_test.go | 35 ++++ resources/process_resource.go | 33 ++-- resources/process_resource_test.go | 22 +++ resources/quota_resource.go | 8 + resources/quota_resource_test.go | 24 ++- resources/space_quota_resource.go | 3 + resources/task_resource.go | 2 + util/manifestparser/application.go | 1 + util/manifestparser/application_test.go | 29 ++++ util/manifestparser/process.go | 1 + util/manifestparser/process_test.go | 1 - 70 files changed, 1382 insertions(+), 318 deletions(-) create mode 100644 actor/v7pushaction/handle_log_rate_limit_override.go create mode 100644 actor/v7pushaction/handle_log_rate_limit_override_test.go create mode 100644 command/flag/bytes_with_unlimited.go create mode 100644 command/flag/bytes_with_unlimited_test.go rename command/flag/{memory_with_unlimited.go => megabytes_with_unlimited.go} (63%) rename command/flag/{memory_with_unlimited_test.go => megabytes_with_unlimited_test.go} (58%) create mode 100644 integration/v7/push/log_rate_limit_flag_test.go diff --git a/actor/v7action/organization_quota.go b/actor/v7action/organization_quota.go index 1352d43dc46..2e2f7953b4f 100644 --- a/actor/v7action/organization_quota.go +++ b/actor/v7action/organization_quota.go @@ -15,6 +15,7 @@ type QuotaLimits struct { TotalServiceInstances *types.NullInt TotalRoutes *types.NullInt TotalReservedPorts *types.NullInt + TotalLogVolume *types.NullInt } func (actor Actor) ApplyOrganizationQuotaByName(quotaName string, orgGUID string) (Warnings, error) { @@ -119,6 +120,7 @@ func createQuotaStruct(name string, limits QuotaLimits) resources.OrganizationQu TotalMemory: limits.TotalMemoryInMB, InstanceMemory: limits.PerProcessMemoryInMB, TotalAppInstances: limits.TotalInstances, + TotalLogVolume: limits.TotalLogVolume, } ServiceLimit := resources.ServiceLimit{ TotalServiceInstances: limits.TotalServiceInstances, @@ -164,6 +166,7 @@ func convertUnlimitedToNil(apps *resources.AppLimit, routes *resources.RouteLimi apps.TotalMemory, apps.InstanceMemory, apps.TotalAppInstances, + apps.TotalLogVolume, services.TotalServiceInstances, routes.TotalRoutes, routes.TotalReservedPorts, diff --git a/actor/v7action/organization_quota_test.go b/actor/v7action/organization_quota_test.go index 6cfe1fd21a9..8ff8a897296 100644 --- a/actor/v7action/organization_quota_test.go +++ b/actor/v7action/organization_quota_test.go @@ -399,6 +399,7 @@ var _ = Describe("Organization Quota Actions", func() { PaidServicesAllowed: &trueValue, TotalRoutes: &types.NullInt{Value: 6, IsSet: true}, TotalReservedPorts: &types.NullInt{Value: 5, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: 512, IsSet: true}, } }) @@ -438,6 +439,7 @@ var _ = Describe("Organization Quota Actions", func() { TotalMemory: &types.NullInt{Value: 0, IsSet: true}, InstanceMemory: nil, TotalAppInstances: nil, + TotalLogVolume: nil, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 0, IsSet: true}, @@ -480,6 +482,7 @@ var _ = Describe("Organization Quota Actions", func() { TotalServiceInstances: &types.NullInt{Value: -1, IsSet: true}, TotalRoutes: &types.NullInt{Value: -1, IsSet: true}, TotalReservedPorts: &types.NullInt{Value: -1, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: -1, IsSet: true}, } ccv3Quota = resources.OrganizationQuota{ Quota: resources.Quota{ @@ -488,6 +491,7 @@ var _ = Describe("Organization Quota Actions", func() { TotalMemory: &types.NullInt{Value: 0, IsSet: false}, InstanceMemory: &types.NullInt{Value: 0, IsSet: false}, TotalAppInstances: &types.NullInt{Value: 0, IsSet: false}, + TotalLogVolume: &types.NullInt{Value: 0, IsSet: false}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 0, IsSet: false}, @@ -506,7 +510,7 @@ var _ = Describe("Organization Quota Actions", func() { ) }) - It("call the create endpoint with the respective values and returns warnings", func() { + It("calls the create endpoint with the respective values and returns warnings", func() { Expect(fakeCloudControllerClient.CreateOrganizationQuotaCallCount()).To(Equal(1)) Expect(warnings).To(ConsistOf("some-quota-warning")) @@ -516,7 +520,7 @@ var _ = Describe("Organization Quota Actions", func() { }) }) - When("The create org quota endpoint succeeds", func() { + When("the create org quota endpoint succeeds", func() { var ( ccv3Quota resources.OrganizationQuota ) @@ -528,6 +532,7 @@ var _ = Describe("Organization Quota Actions", func() { TotalMemory: &types.NullInt{Value: 2048, IsSet: true}, InstanceMemory: &types.NullInt{Value: 1024, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 0, IsSet: false}, + TotalLogVolume: &types.NullInt{Value: 512, IsSet: true}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 0, IsSet: true}, @@ -546,7 +551,7 @@ var _ = Describe("Organization Quota Actions", func() { ) }) - It("call the create endpoint with the respective values and returns warnings", func() { + It("calls the create endpoint with the respective values and returns warnings", func() { Expect(fakeCloudControllerClient.CreateOrganizationQuotaCallCount()).To(Equal(1)) Expect(warnings).To(ConsistOf("some-quota-warning")) @@ -577,6 +582,7 @@ var _ = Describe("Organization Quota Actions", func() { PaidServicesAllowed: &trueValue, TotalRoutes: &types.NullInt{Value: 6, IsSet: true}, TotalReservedPorts: &types.NullInt{Value: 5, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: 64, IsSet: true}, } fakeCloudControllerClient.GetOrganizationQuotasReturns( @@ -622,6 +628,7 @@ var _ = Describe("Organization Quota Actions", func() { TotalMemory: nil, InstanceMemory: nil, TotalAppInstances: nil, + TotalLogVolume: nil, }, Services: resources.ServiceLimit{ TotalServiceInstances: nil, @@ -669,6 +676,7 @@ var _ = Describe("Organization Quota Actions", func() { TotalServiceInstances: &types.NullInt{Value: -1, IsSet: true}, TotalRoutes: &types.NullInt{Value: -1, IsSet: true}, TotalReservedPorts: &types.NullInt{Value: -1, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: -1, IsSet: true}, } ccv3Quota = resources.OrganizationQuota{ Quota: resources.Quota{ @@ -677,6 +685,7 @@ var _ = Describe("Organization Quota Actions", func() { TotalMemory: &types.NullInt{Value: 0, IsSet: false}, InstanceMemory: &types.NullInt{Value: 0, IsSet: false}, TotalAppInstances: &types.NullInt{Value: 0, IsSet: false}, + TotalLogVolume: &types.NullInt{Value: 0, IsSet: false}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 0, IsSet: false}, @@ -722,6 +731,7 @@ var _ = Describe("Organization Quota Actions", func() { TotalMemory: &types.NullInt{Value: 2048, IsSet: true}, InstanceMemory: &types.NullInt{Value: 1024, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 0, IsSet: false}, + TotalLogVolume: &types.NullInt{Value: 64, IsSet: true}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 0, IsSet: true}, diff --git a/actor/v7action/space_quota.go b/actor/v7action/space_quota.go index 78f5acc38c6..d7aaf5af9ea 100644 --- a/actor/v7action/space_quota.go +++ b/actor/v7action/space_quota.go @@ -31,6 +31,7 @@ func (actor Actor) CreateSpaceQuota(spaceQuotaName string, orgGuid string, limit TotalMemory: limits.TotalMemoryInMB, InstanceMemory: limits.PerProcessMemoryInMB, TotalAppInstances: limits.TotalInstances, + TotalLogVolume: limits.TotalLogVolume, }, Services: resources.ServiceLimit{ TotalServiceInstances: limits.TotalServiceInstances, @@ -137,6 +138,7 @@ func (actor Actor) UpdateSpaceQuota(currentName, orgGUID, newName string, limits TotalMemory: limits.TotalMemoryInMB, InstanceMemory: limits.PerProcessMemoryInMB, TotalAppInstances: limits.TotalInstances, + TotalLogVolume: limits.TotalLogVolume, }, Services: resources.ServiceLimit{ TotalServiceInstances: limits.TotalServiceInstances, diff --git a/actor/v7action/space_quota_test.go b/actor/v7action/space_quota_test.go index fed2d91c0c2..001c70f64ca 100644 --- a/actor/v7action/space_quota_test.go +++ b/actor/v7action/space_quota_test.go @@ -151,6 +151,7 @@ var _ = Describe("Space Quota Actions", func() { TotalServiceInstances: &types.NullInt{IsSet: true, Value: 6}, TotalRoutes: &types.NullInt{IsSet: true, Value: 8}, TotalReservedPorts: &types.NullInt{IsSet: true, Value: 9}, + TotalLogVolume: &types.NullInt{IsSet: true, Value: 10}, } }) @@ -167,6 +168,7 @@ var _ = Describe("Space Quota Actions", func() { TotalMemory: &types.NullInt{IsSet: true, Value: 2}, InstanceMemory: &types.NullInt{IsSet: true, Value: 3}, TotalAppInstances: &types.NullInt{IsSet: true, Value: 4}, + TotalLogVolume: &types.NullInt{IsSet: true, Value: 10}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{IsSet: true, Value: 6}, @@ -201,6 +203,7 @@ var _ = Describe("Space Quota Actions", func() { TotalMemory: &types.NullInt{Value: 0, IsSet: true}, InstanceMemory: nil, TotalAppInstances: nil, + TotalLogVolume: nil, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 0, IsSet: true}, @@ -244,6 +247,7 @@ var _ = Describe("Space Quota Actions", func() { TotalServiceInstances: &types.NullInt{Value: -1, IsSet: true}, TotalRoutes: &types.NullInt{Value: -1, IsSet: true}, TotalReservedPorts: &types.NullInt{Value: -1, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: -1, IsSet: true}, } ccv3Quota = resources.SpaceQuota{ Quota: resources.Quota{ @@ -252,6 +256,7 @@ var _ = Describe("Space Quota Actions", func() { TotalMemory: &types.NullInt{Value: 0, IsSet: false}, InstanceMemory: &types.NullInt{Value: 0, IsSet: false}, TotalAppInstances: &types.NullInt{Value: 0, IsSet: false}, + TotalLogVolume: &types.NullInt{Value: 0, IsSet: false}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 0, IsSet: false}, @@ -607,6 +612,7 @@ var _ = Describe("Space Quota Actions", func() { PaidServicesAllowed: &trueValue, TotalRoutes: &types.NullInt{Value: 6, IsSet: true}, TotalReservedPorts: &types.NullInt{Value: 5, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: 512, IsSet: true}, } fakeCloudControllerClient.GetSpaceQuotasReturns( @@ -652,6 +658,7 @@ var _ = Describe("Space Quota Actions", func() { TotalMemory: nil, InstanceMemory: nil, TotalAppInstances: nil, + TotalLogVolume: nil, }, Services: resources.ServiceLimit{ TotalServiceInstances: nil, @@ -699,6 +706,7 @@ var _ = Describe("Space Quota Actions", func() { TotalServiceInstances: &types.NullInt{Value: -1, IsSet: true}, TotalRoutes: &types.NullInt{Value: -1, IsSet: true}, TotalReservedPorts: &types.NullInt{Value: -1, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: -1, IsSet: true}, } ccv3Quota = resources.SpaceQuota{ @@ -708,6 +716,7 @@ var _ = Describe("Space Quota Actions", func() { TotalMemory: &types.NullInt{Value: 0, IsSet: false}, InstanceMemory: &types.NullInt{Value: 0, IsSet: false}, TotalAppInstances: &types.NullInt{Value: 0, IsSet: false}, + TotalLogVolume: &types.NullInt{Value: 0, IsSet: false}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 0, IsSet: false}, @@ -754,6 +763,7 @@ var _ = Describe("Space Quota Actions", func() { TotalMemory: &types.NullInt{Value: 2048, IsSet: true}, InstanceMemory: &types.NullInt{Value: 1024, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 0, IsSet: false}, + TotalLogVolume: &types.NullInt{Value: 512, IsSet: true}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 0, IsSet: true}, @@ -802,6 +812,7 @@ var _ = Describe("Space Quota Actions", func() { TotalMemory: &types.NullInt{Value: 2048, IsSet: true}, InstanceMemory: &types.NullInt{Value: 1024, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 0, IsSet: false}, + TotalLogVolume: &types.NullInt{Value: 512, IsSet: true}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 0, IsSet: true}, diff --git a/actor/v7pushaction/actor.go b/actor/v7pushaction/actor.go index 00438dea3b2..f2c74ef9cea 100644 --- a/actor/v7pushaction/actor.go +++ b/actor/v7pushaction/actor.go @@ -50,6 +50,7 @@ func NewActor(v3Actor V7Actor, sharedActor SharedActor) *Actor { HandleHealthCheckTimeoutOverride, HandleMemoryOverride, HandleDiskOverride, + HandleLogRateLimitOverride, HandleNoRouteOverride, HandleRandomRouteOverride, HandleTaskOverride, diff --git a/actor/v7pushaction/handle_log_rate_limit_override.go b/actor/v7pushaction/handle_log_rate_limit_override.go new file mode 100644 index 00000000000..9e80cbfc805 --- /dev/null +++ b/actor/v7pushaction/handle_log_rate_limit_override.go @@ -0,0 +1,24 @@ +package v7pushaction + +import ( + "code.cloudfoundry.org/cli/command/translatableerror" + "code.cloudfoundry.org/cli/util/manifestparser" +) + +func HandleLogRateLimitOverride(manifest manifestparser.Manifest, overrides FlagOverrides) (manifestparser.Manifest, error) { + if overrides.LogRateLimit != "" { + if manifest.ContainsMultipleApps() { + return manifest, translatableerror.CommandLineArgsWithMultipleAppsError{} + } + + webProcess := manifest.GetFirstAppWebProcess() + if webProcess != nil { + webProcess.LogRateLimit = overrides.LogRateLimit + } else { + app := manifest.GetFirstApp() + app.LogRateLimit = overrides.LogRateLimit + } + } + + return manifest, nil +} diff --git a/actor/v7pushaction/handle_log_rate_limit_override_test.go b/actor/v7pushaction/handle_log_rate_limit_override_test.go new file mode 100644 index 00000000000..877b1f7d07a --- /dev/null +++ b/actor/v7pushaction/handle_log_rate_limit_override_test.go @@ -0,0 +1,149 @@ +package v7pushaction_test + +import ( + "code.cloudfoundry.org/cli/command/translatableerror" + "code.cloudfoundry.org/cli/util/manifestparser" + + . "code.cloudfoundry.org/cli/actor/v7pushaction" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("HandleLogRateLimitOverride", func() { + var ( + originalManifest manifestparser.Manifest + transformedManifest manifestparser.Manifest + overrides FlagOverrides + executeErr error + ) + + BeforeEach(func() { + originalManifest = manifestparser.Manifest{} + overrides = FlagOverrides{} + }) + + JustBeforeEach(func() { + transformedManifest, executeErr = HandleLogRateLimitOverride(originalManifest, overrides) + }) + + When("log rate limit is not set on a flag override", func() { + BeforeEach(func() { + originalManifest.Applications = []manifestparser.Application{ + { + Processes: []manifestparser.Process{ + {Type: "web"}, + {Type: "worker", LogRateLimit: "1B"}, + }, + }, + } + }) + + It("does not change the manifest", func() { + Expect(executeErr).ToNot(HaveOccurred()) + Expect(transformedManifest.Applications).To(ConsistOf( + manifestparser.Application{ + Processes: []manifestparser.Process{ + {Type: "web"}, + {Type: "worker", LogRateLimit: "1B"}, + }, + }, + )) + }) + }) + + When("manifest web process does not specify log rate limit", func() { + BeforeEach(func() { + overrides.LogRateLimit = "64K" + + originalManifest.Applications = []manifestparser.Application{ + { + Processes: []manifestparser.Process{ + {Type: "web"}, + }, + }, + } + }) + + It("changes the log rate limit of the web process in the manifest", func() { + Expect(executeErr).ToNot(HaveOccurred()) + Expect(transformedManifest.Applications).To(ConsistOf( + manifestparser.Application{ + Processes: []manifestparser.Process{ + {Type: "web", LogRateLimit: "64K"}, + }, + }, + )) + }) + }) + + When("manifest app has only non-web processes", func() { + BeforeEach(func() { + overrides.LogRateLimit = "32B" + + originalManifest.Applications = []manifestparser.Application{ + { + Processes: []manifestparser.Process{ + {Type: "worker"}, + }, + }, + } + }) + + It("changes the log rate limit of the app in the manifest", func() { + Expect(executeErr).ToNot(HaveOccurred()) + Expect(transformedManifest.Applications).To(ConsistOf( + manifestparser.Application{ + LogRateLimit: "32B", + Processes: []manifestparser.Process{ + {Type: "worker"}, + }, + }, + )) + }) + }) + + When("manifest app has web and non-web processes", func() { + BeforeEach(func() { + overrides.LogRateLimit = "4MB" + + originalManifest.Applications = []manifestparser.Application{ + { + Processes: []manifestparser.Process{ + {Type: "worker"}, + {Type: "web"}, + }, + LogRateLimit: "1GB", + }, + } + }) + + It("changes the log rate limit of the web process in the manifest", func() { + Expect(executeErr).ToNot(HaveOccurred()) + Expect(transformedManifest.Applications).To(ConsistOf( + manifestparser.Application{ + Processes: []manifestparser.Process{ + {Type: "worker"}, + {Type: "web", LogRateLimit: "4MB"}, + }, + LogRateLimit: "1GB", + }, + )) + }) + }) + + When("there are multiple apps in the manifest", func() { + BeforeEach(func() { + overrides.LogRateLimit = "64M" + + originalManifest.Applications = []manifestparser.Application{ + {}, + {}, + } + }) + + It("returns an error", func() { + Expect(executeErr).To(MatchError(translatableerror.CommandLineArgsWithMultipleAppsError{})) + }) + }) +}) diff --git a/actor/v7pushaction/handle_memory_override.go b/actor/v7pushaction/handle_memory_override.go index 82944bba6eb..67c12f758be 100644 --- a/actor/v7pushaction/handle_memory_override.go +++ b/actor/v7pushaction/handle_memory_override.go @@ -1,7 +1,6 @@ package v7pushaction import ( - //"code.cloudfoundry.org/cli/command/translatableerror" "code.cloudfoundry.org/cli/command/translatableerror" "code.cloudfoundry.org/cli/util/manifestparser" ) diff --git a/actor/v7pushaction/push_plan.go b/actor/v7pushaction/push_plan.go index 19d4a32d298..eacb52d577a 100644 --- a/actor/v7pushaction/push_plan.go +++ b/actor/v7pushaction/push_plan.go @@ -59,6 +59,7 @@ type FlagOverrides struct { Vars []template.VarKV NoManifest bool Task bool + LogRateLimit string } func (state PushPlan) String() string { diff --git a/api/cloudcontroller/ccv3/organization_quota_test.go b/api/cloudcontroller/ccv3/organization_quota_test.go index 9d509d62a9f..46460826eec 100644 --- a/api/cloudcontroller/ccv3/organization_quota_test.go +++ b/api/cloudcontroller/ccv3/organization_quota_test.go @@ -60,7 +60,8 @@ var _ = Describe("Organization Quotas", func() { "total_memory_in_mb": 5120, "per_process_memory_in_mb": 1024, "total_instances": 10, - "per_app_tasks": 5 + "per_app_tasks": 5, + "log_rate_limit_in_bytes_per_second": 8 }, "services": { "paid_services_allowed": true, @@ -103,7 +104,8 @@ var _ = Describe("Organization Quotas", func() { "total_memory_in_mb": 10240, "per_process_memory_in_mb": 1024, "total_instances": 8, - "per_app_tasks": 5 + "per_app_tasks": 5, + "log_rate_limit_in_bytes_per_second": 16 }, "services": { "paid_services_allowed": false, @@ -156,6 +158,7 @@ var _ = Describe("Organization Quotas", func() { TotalMemory: &types.NullInt{Value: 5120, IsSet: true}, InstanceMemory: &types.NullInt{Value: 1024, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 10, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: 8, IsSet: true}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 10, IsSet: true}, @@ -175,6 +178,7 @@ var _ = Describe("Organization Quotas", func() { TotalMemory: &types.NullInt{Value: 10240, IsSet: true}, InstanceMemory: &types.NullInt{Value: 1024, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 8, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: 16, IsSet: true}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 8, IsSet: true}, @@ -211,7 +215,8 @@ var _ = Describe("Organization Quotas", func() { "total_memory_in_mb": 10240, "per_process_memory_in_mb": 1024, "total_instances": 8, - "per_app_tasks": 5 + "per_app_tasks": 5, + "log_rate_limit_in_bytes_per_second": 8 }, "services": { "paid_services_allowed": false, @@ -257,6 +262,7 @@ var _ = Describe("Organization Quotas", func() { TotalMemory: &types.NullInt{Value: 10240, IsSet: true}, InstanceMemory: &types.NullInt{Value: 1024, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 8, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: 8, IsSet: true}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 8, IsSet: true}, @@ -337,7 +343,8 @@ var _ = Describe("Organization Quotas", func() { "total_memory_in_mb": 5120, "per_process_memory_in_mb": 1024, "total_instances": 10, - "per_app_tasks": 5 + "per_app_tasks": 5, + "log_rate_limit_in_bytes_per_second": 8 }, "services": { "paid_services_allowed": true, @@ -384,6 +391,7 @@ var _ = Describe("Organization Quotas", func() { TotalMemory: &types.NullInt{Value: 5120, IsSet: true}, InstanceMemory: &types.NullInt{Value: 1024, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 10, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: 8, IsSet: true}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 10, IsSet: true}, @@ -460,6 +468,7 @@ var _ = Describe("Organization Quotas", func() { TotalMemory: &types.NullInt{Value: 2048, IsSet: true}, InstanceMemory: &types.NullInt{Value: 1024, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 0, IsSet: false}, + TotalLogVolume: &types.NullInt{Value: 0, IsSet: false}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 0, IsSet: true}, @@ -488,7 +497,8 @@ var _ = Describe("Organization Quotas", func() { "total_memory_in_mb": 2048, "per_process_memory_in_mb": 1024, "total_instances": null, - "per_app_tasks": null + "per_app_tasks": null, + "log_rate_limit_in_bytes_per_second": null }, "services": { "paid_services_allowed": true, @@ -512,9 +522,10 @@ var _ = Describe("Organization Quotas", func() { expectedBody := map[string]interface{}{ "name": "elephant-trunk", "apps": map[string]interface{}{ - "total_memory_in_mb": 2048, - "per_process_memory_in_mb": 1024, - "total_instances": nil, + "total_memory_in_mb": 2048, + "per_process_memory_in_mb": 1024, + "total_instances": nil, + "log_rate_limit_in_bytes_per_second": nil, }, "services": map[string]interface{}{ "paid_services_allowed": true, @@ -711,6 +722,7 @@ var _ = Describe("Organization Quotas", func() { TotalMemory: &types.NullInt{Value: 2048, IsSet: true}, InstanceMemory: &types.NullInt{Value: 1024, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 0, IsSet: false}, + TotalLogVolume: &types.NullInt{Value: 8, IsSet: true}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 0, IsSet: true}, @@ -735,7 +747,8 @@ var _ = Describe("Organization Quotas", func() { "total_memory_in_mb": 2048, "per_process_memory_in_mb": 1024, "total_instances": null, - "per_app_tasks": null + "per_app_tasks": null, + "log_rate_limit_in_bytes_per_second": 8 }, "services": { "paid_services_allowed": true, @@ -759,9 +772,10 @@ var _ = Describe("Organization Quotas", func() { expectedBody := map[string]interface{}{ "name": "elephant-trunk", "apps": map[string]interface{}{ - "total_memory_in_mb": 2048, - "per_process_memory_in_mb": 1024, - "total_instances": nil, + "total_memory_in_mb": 2048, + "per_process_memory_in_mb": 1024, + "total_instances": nil, + "log_rate_limit_in_bytes_per_second": 8, }, "services": map[string]interface{}{ "paid_services_allowed": true, @@ -791,6 +805,7 @@ var _ = Describe("Organization Quotas", func() { TotalMemory: &types.NullInt{IsSet: true, Value: 2048}, InstanceMemory: &types.NullInt{IsSet: true, Value: 1024}, TotalAppInstances: &types.NullInt{IsSet: false, Value: 0}, + TotalLogVolume: &types.NullInt{Value: 8, IsSet: true}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{IsSet: true, Value: 0}, diff --git a/api/cloudcontroller/ccv3/process_instance.go b/api/cloudcontroller/ccv3/process_instance.go index 572ce04b8e3..56f7c221b77 100644 --- a/api/cloudcontroller/ccv3/process_instance.go +++ b/api/cloudcontroller/ccv3/process_instance.go @@ -29,8 +29,12 @@ type ProcessInstance struct { IsolationSegment string // MemoryQuota is the maximum memory the instance is allowed to use. MemoryQuota uint64 - // DiskUsage is the current memory usage of the instance. + // MemoryUsage is the current memory usage of the instance. MemoryUsage uint64 + // LogRateLimit is the maximum rate that the instance is allowed to log. + LogRateLimit int64 + // LogRate is the current rate that the instance is logging. + LogRate uint64 // State is the state of the instance. State constant.ProcessInstanceState // Type is the process type for the instance. @@ -47,13 +51,15 @@ func (instance *ProcessInstance) UnmarshalJSON(data []byte) error { Index int64 `json:"index"` IsolationSegment string `json:"isolation_segment"` MemQuota uint64 `json:"mem_quota"` + LogRateLimit int64 `json:"log_rate_limit"` State string `json:"state"` Type string `json:"type"` Uptime int64 `json:"uptime"` Usage struct { - CPU float64 `json:"cpu"` - Mem uint64 `json:"mem"` - Disk uint64 `json:"disk"` + CPU float64 `json:"cpu"` + Mem uint64 `json:"mem"` + Disk uint64 `json:"disk"` + LogRate uint64 `json:"log_rate"` } `json:"usage"` } @@ -70,6 +76,8 @@ func (instance *ProcessInstance) UnmarshalJSON(data []byte) error { instance.IsolationSegment = inputInstance.IsolationSegment instance.MemoryQuota = inputInstance.MemQuota instance.MemoryUsage = inputInstance.Usage.Mem + instance.LogRateLimit = inputInstance.LogRateLimit + instance.LogRate = inputInstance.Usage.LogRate instance.State = constant.ProcessInstanceState(inputInstance.State) instance.Type = inputInstance.Type instance.Uptime, err = time.ParseDuration(fmt.Sprintf("%ds", inputInstance.Uptime)) diff --git a/api/cloudcontroller/ccv3/process_instance_test.go b/api/cloudcontroller/ccv3/process_instance_test.go index a92935a8da3..2280a979348 100644 --- a/api/cloudcontroller/ccv3/process_instance_test.go +++ b/api/cloudcontroller/ccv3/process_instance_test.go @@ -93,10 +93,12 @@ var _ = Describe("ProcessInstance", func() { "usage": { "cpu": 0.01, "mem": 1000000, - "disk": 2000000 + "disk": 2000000, + "log_rate": 5000 }, "mem_quota": 2000000, "disk_quota": 4000000, + "log_rate_limit": 10000, "isolation_segment": "example_iso_segment", "index": 0, "uptime": 123, @@ -108,10 +110,12 @@ var _ = Describe("ProcessInstance", func() { "usage": { "cpu": 0.02, "mem": 8000000, - "disk": 16000000 + "disk": 16000000, + "log_rate": 32000 }, "mem_quota": 16000000, "disk_quota": 32000000, + "log_rate_limit": 64000, "isolation_segment": "example_iso_segment", "index": 1, "uptime": 456 @@ -139,6 +143,8 @@ var _ = Describe("ProcessInstance", func() { IsolationSegment: "example_iso_segment", MemoryQuota: 2000000, MemoryUsage: 1000000, + LogRateLimit: 10000, + LogRate: 5000, State: constant.ProcessInstanceRunning, Type: "web", Uptime: 123 * time.Second, @@ -151,6 +157,8 @@ var _ = Describe("ProcessInstance", func() { IsolationSegment: "example_iso_segment", MemoryQuota: 16000000, MemoryUsage: 8000000, + LogRateLimit: 64000, + LogRate: 32000, State: constant.ProcessInstanceRunning, Type: "web", Uptime: 456 * time.Second, diff --git a/api/cloudcontroller/ccv3/process_test.go b/api/cloudcontroller/ccv3/process_test.go index 2502c8e57a1..62eb3af85b6 100644 --- a/api/cloudcontroller/ccv3/process_test.go +++ b/api/cloudcontroller/ccv3/process_test.go @@ -41,6 +41,7 @@ var _ = Describe("Process", func() { "instances": 22, "memory_in_mb": 32, "disk_in_mb": 1024, + "log_rate_limit_in_bytes_per_second": 512, "relationships": { "app": { "data": { @@ -76,6 +77,7 @@ var _ = Describe("Process", func() { "Instances": Equal(types.NullInt{Value: 22, IsSet: true}), "MemoryInMB": Equal(types.NullUint64{Value: 32, IsSet: true}), "DiskInMB": Equal(types.NullUint64{Value: 1024, IsSet: true}), + "LogRateLimitInBPS": Equal(types.NullInt{Value: 512, IsSet: true}), "HealthCheckType": Equal(constant.HTTP), "HealthCheckEndpoint": Equal("/health"), "HealthCheckInvocationTimeout": BeEquivalentTo(42), @@ -135,15 +137,17 @@ var _ = Describe("Process", func() { When("providing all scale options", func() { BeforeEach(func() { passedProcess = resources.Process{ - Type: constant.ProcessTypeWeb, - Instances: types.NullInt{Value: 2, IsSet: true}, - MemoryInMB: types.NullUint64{Value: 100, IsSet: true}, - DiskInMB: types.NullUint64{Value: 200, IsSet: true}, + Type: constant.ProcessTypeWeb, + Instances: types.NullInt{Value: 2, IsSet: true}, + MemoryInMB: types.NullUint64{Value: 100, IsSet: true}, + DiskInMB: types.NullUint64{Value: 200, IsSet: true}, + LogRateLimitInBPS: types.NullInt{Value: 256, IsSet: true}, } expectedBody := `{ "instances": 2, "memory_in_mb": 100, - "disk_in_mb": 200 + "disk_in_mb": 200, + "log_rate_limit_in_bytes_per_second": 256 }` response := `{ "guid": "some-process-guid" @@ -168,15 +172,17 @@ var _ = Describe("Process", func() { When("providing all scale options with 0 values", func() { BeforeEach(func() { passedProcess = resources.Process{ - Type: constant.ProcessTypeWeb, - Instances: types.NullInt{Value: 0, IsSet: true}, - MemoryInMB: types.NullUint64{Value: 0, IsSet: true}, - DiskInMB: types.NullUint64{Value: 0, IsSet: true}, + Type: constant.ProcessTypeWeb, + Instances: types.NullInt{Value: 0, IsSet: true}, + MemoryInMB: types.NullUint64{Value: 0, IsSet: true}, + DiskInMB: types.NullUint64{Value: 0, IsSet: true}, + LogRateLimitInBPS: types.NullInt{Value: 0, IsSet: true}, } expectedBody := `{ "instances": 0, "memory_in_mb": 0, - "disk_in_mb": 0 + "disk_in_mb": 0, + "log_rate_limit_in_bytes_per_second": 0 }` response := `{ "guid": "some-process-guid" @@ -296,6 +302,7 @@ var _ = Describe("Process", func() { "instances": 22, "memory_in_mb": 32, "disk_in_mb": 1024, + "log_rate_limit_in_bytes_per_second": 64, "relationships": { "app": { "data": { @@ -331,6 +338,7 @@ var _ = Describe("Process", func() { "Instances": Equal(types.NullInt{Value: 22, IsSet: true}), "MemoryInMB": Equal(types.NullUint64{Value: 32, IsSet: true}), "DiskInMB": Equal(types.NullUint64{Value: 1024, IsSet: true}), + "LogRateLimitInBPS": Equal(types.NullInt{Value: 64, IsSet: true}), "HealthCheckType": Equal(constant.HTTP), "HealthCheckEndpoint": Equal("/health"), "HealthCheckInvocationTimeout": BeEquivalentTo(42), @@ -425,6 +433,7 @@ var _ = Describe("Process", func() { "type": "web", "command": "[PRIVATE DATA HIDDEN IN LISTS]", "memory_in_mb": 32, + "log_rate_limit_in_bytes_per_second": 64, "health_check": { "type": "port", "data": { @@ -438,6 +447,7 @@ var _ = Describe("Process", func() { "type": "worker", "command": "[PRIVATE DATA HIDDEN IN LISTS]", "memory_in_mb": 64, + "log_rate_limit_in_bytes_per_second": 128, "health_check": { "type": "http", "data": { @@ -459,6 +469,7 @@ var _ = Describe("Process", func() { "type": "console", "command": "[PRIVATE DATA HIDDEN IN LISTS]", "memory_in_mb": 128, + "log_rate_limit_in_bytes_per_second": 256, "health_check": { "type": "process", "data": { @@ -493,6 +504,7 @@ var _ = Describe("Process", func() { Type: constant.ProcessTypeWeb, Command: types.FilteredString{IsSet: true, Value: "[PRIVATE DATA HIDDEN IN LISTS]"}, MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, + LogRateLimitInBPS: types.NullInt{Value: 64, IsSet: true}, HealthCheckType: constant.Port, HealthCheckTimeout: 0, }, @@ -501,6 +513,7 @@ var _ = Describe("Process", func() { Type: "worker", Command: types.FilteredString{IsSet: true, Value: "[PRIVATE DATA HIDDEN IN LISTS]"}, MemoryInMB: types.NullUint64{Value: 64, IsSet: true}, + LogRateLimitInBPS: types.NullInt{Value: 128, IsSet: true}, HealthCheckType: constant.HTTP, HealthCheckEndpoint: "/health", HealthCheckTimeout: 60, @@ -510,6 +523,7 @@ var _ = Describe("Process", func() { Type: "console", Command: types.FilteredString{IsSet: true, Value: "[PRIVATE DATA HIDDEN IN LISTS]"}, MemoryInMB: types.NullUint64{Value: 128, IsSet: true}, + LogRateLimitInBPS: types.NullInt{Value: 256, IsSet: true}, HealthCheckType: constant.Process, HealthCheckTimeout: 90, }, @@ -560,6 +574,7 @@ var _ = Describe("Process", func() { "type": "web", "command": "[PRIVATE DATA HIDDEN IN LISTS]", "memory_in_mb": 32, + "log_rate_limit_in_bytes_per_second": 64, "health_check": { "type": "port", "data": { @@ -573,6 +588,7 @@ var _ = Describe("Process", func() { "type": "web", "command": "[PRIVATE DATA HIDDEN IN LISTS]", "memory_in_mb": 32, + "log_rate_limit_in_bytes_per_second": 64, "health_check": { "type": "port", "data": { @@ -586,6 +602,7 @@ var _ = Describe("Process", func() { "type": "worker", "command": "[PRIVATE DATA HIDDEN IN LISTS]", "memory_in_mb": 64, + "log_rate_limit_in_bytes_per_second": 128, "health_check": { "type": "http", "data": { @@ -608,6 +625,7 @@ var _ = Describe("Process", func() { "type": "console", "command": "[PRIVATE DATA HIDDEN IN LISTS]", "memory_in_mb": 128, + "log_rate_limit_in_bytes_per_second": 256, "health_check": { "type": "process", "data": { @@ -661,6 +679,7 @@ var _ = Describe("Process", func() { Type: constant.ProcessTypeWeb, Command: types.FilteredString{IsSet: true, Value: "[PRIVATE DATA HIDDEN IN LISTS]"}, MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, + LogRateLimitInBPS: types.NullInt{Value: 64, IsSet: true}, HealthCheckType: constant.Port, HealthCheckTimeout: 0, }, @@ -669,6 +688,7 @@ var _ = Describe("Process", func() { Type: "worker", Command: types.FilteredString{IsSet: true, Value: "[PRIVATE DATA HIDDEN IN LISTS]"}, MemoryInMB: types.NullUint64{Value: 64, IsSet: true}, + LogRateLimitInBPS: types.NullInt{Value: 128, IsSet: true}, HealthCheckType: constant.HTTP, HealthCheckEndpoint: "/health", HealthCheckTimeout: 60, @@ -678,6 +698,7 @@ var _ = Describe("Process", func() { Type: "console", Command: types.FilteredString{IsSet: true, Value: "[PRIVATE DATA HIDDEN IN LISTS]"}, MemoryInMB: types.NullUint64{Value: 128, IsSet: true}, + LogRateLimitInBPS: types.NullInt{Value: 256, IsSet: true}, HealthCheckType: constant.Process, HealthCheckTimeout: 90, }, diff --git a/api/cloudcontroller/ccv3/space_quota_test.go b/api/cloudcontroller/ccv3/space_quota_test.go index 26ba72d6126..21069e1cf2f 100644 --- a/api/cloudcontroller/ccv3/space_quota_test.go +++ b/api/cloudcontroller/ccv3/space_quota_test.go @@ -130,7 +130,7 @@ var _ = Describe("Space Quotas", func() { }) - Describe("CreateSpaceQuotas", func() { + Describe("CreateSpaceQuota", func() { JustBeforeEach(func() { createdSpaceQuota, warnings, executeErr = client.CreateSpaceQuota(inputSpaceQuota) }) @@ -144,6 +144,7 @@ var _ = Describe("Space Quotas", func() { TotalMemory: &types.NullInt{IsSet: true, Value: 2}, InstanceMemory: &types.NullInt{IsSet: true, Value: 3}, TotalAppInstances: &types.NullInt{IsSet: true, Value: 4}, + TotalLogVolume: &types.NullInt{IsSet: true, Value: 8}, }, Services: resources.ServiceLimit{ PaidServicePlans: &trueValue, @@ -166,7 +167,8 @@ var _ = Describe("Space Quotas", func() { "total_memory_in_mb": 2, "per_process_memory_in_mb": 3, "total_instances": 4, - "per_app_tasks": 900 + "per_app_tasks": 900, + "log_rate_limit_in_bytes_per_second": 8 }, "services": { "paid_services_allowed": true, @@ -200,9 +202,10 @@ var _ = Describe("Space Quotas", func() { expectedBody := map[string]interface{}{ "name": "my-space-quota", "apps": map[string]interface{}{ - "total_memory_in_mb": 2, - "per_process_memory_in_mb": 3, - "total_instances": 4, + "total_memory_in_mb": 2, + "per_process_memory_in_mb": 3, + "total_instances": 4, + "log_rate_limit_in_bytes_per_second": 8, }, "services": map[string]interface{}{ "paid_services_allowed": true, @@ -242,6 +245,7 @@ var _ = Describe("Space Quotas", func() { TotalMemory: &types.NullInt{IsSet: true, Value: 2}, InstanceMemory: &types.NullInt{IsSet: true, Value: 3}, TotalAppInstances: &types.NullInt{IsSet: true, Value: 4}, + TotalLogVolume: &types.NullInt{IsSet: true, Value: 8}, }, Services: resources.ServiceLimit{ PaidServicePlans: &trueValue, @@ -266,6 +270,7 @@ var _ = Describe("Space Quotas", func() { TotalMemory: &types.NullInt{IsSet: true, Value: 2}, InstanceMemory: &types.NullInt{IsSet: true, Value: 3}, TotalAppInstances: &types.NullInt{IsSet: true, Value: 4}, + TotalLogVolume: &types.NullInt{IsSet: true, Value: 8}, }, Services: resources.ServiceLimit{ PaidServicePlans: &trueValue, @@ -289,7 +294,8 @@ var _ = Describe("Space Quotas", func() { "total_memory_in_mb": 2, "per_process_memory_in_mb": 3, "total_instances": 4, - "per_app_tasks": 5 + "per_app_tasks": 5, + "log_rate_limit_in_bytes_per_second": 8 }, "services": { "paid_services_allowed": true, @@ -324,9 +330,10 @@ var _ = Describe("Space Quotas", func() { expectedBody := map[string]interface{}{ "name": "my-space-quota", "apps": map[string]interface{}{ - "total_memory_in_mb": 2, - "per_process_memory_in_mb": 3, - "total_instances": 4, + "total_memory_in_mb": 2, + "per_process_memory_in_mb": 3, + "total_instances": 4, + "log_rate_limit_in_bytes_per_second": 8, }, "services": map[string]interface{}{ "paid_services_allowed": true, @@ -372,6 +379,7 @@ var _ = Describe("Space Quotas", func() { TotalMemory: &types.NullInt{IsSet: true, Value: 2}, InstanceMemory: &types.NullInt{IsSet: true, Value: 3}, TotalAppInstances: &types.NullInt{IsSet: true, Value: 4}, + TotalLogVolume: &types.NullInt{IsSet: true, Value: 8}, }, Services: resources.ServiceLimit{ PaidServicePlans: &trueValue, @@ -522,7 +530,8 @@ var _ = Describe("Space Quotas", func() { "total_memory_in_mb": 10240, "per_process_memory_in_mb": 1024, "total_instances": 8, - "per_app_tasks": 5 + "per_app_tasks": 5, + "log_rate_limit_in_bytes_per_second": 8 }, "services": { "paid_services_allowed": false, @@ -566,6 +575,7 @@ var _ = Describe("Space Quotas", func() { TotalMemory: &types.NullInt{Value: 10240, IsSet: true}, InstanceMemory: &types.NullInt{Value: 1024, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 8, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: 8, IsSet: true}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 8, IsSet: true}, @@ -663,7 +673,8 @@ var _ = Describe("Space Quotas", func() { "total_memory_in_mb": 5120, "per_process_memory_in_mb": 1024, "total_instances": 10, - "per_app_tasks": 5 + "per_app_tasks": 5, + "log_rate_limit_in_bytes_per_second": 8 }, "services": { "paid_services_allowed": true, @@ -703,7 +714,8 @@ var _ = Describe("Space Quotas", func() { "total_memory_in_mb": 10240, "per_process_memory_in_mb": 1024, "total_instances": 8, - "per_app_tasks": 5 + "per_app_tasks": 5, + "log_rate_limit_in_bytes_per_second": 16 }, "services": { "paid_services_allowed": false, @@ -756,6 +768,7 @@ var _ = Describe("Space Quotas", func() { TotalMemory: &types.NullInt{Value: 5120, IsSet: true}, InstanceMemory: &types.NullInt{Value: 1024, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 10, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: 8, IsSet: true}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 10, IsSet: true}, @@ -776,6 +789,7 @@ var _ = Describe("Space Quotas", func() { TotalMemory: &types.NullInt{Value: 10240, IsSet: true}, InstanceMemory: &types.NullInt{Value: 1024, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 8, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: 16, IsSet: true}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 8, IsSet: true}, @@ -812,7 +826,8 @@ var _ = Describe("Space Quotas", func() { "total_memory_in_mb": 10240, "per_process_memory_in_mb": 1024, "total_instances": 8, - "per_app_tasks": 5 + "per_app_tasks": 5, + "log_rate_limit_in_bytes_per_second": 8 }, "services": { "paid_services_allowed": false, @@ -858,6 +873,7 @@ var _ = Describe("Space Quotas", func() { TotalMemory: &types.NullInt{Value: 10240, IsSet: true}, InstanceMemory: &types.NullInt{Value: 1024, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 8, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: 8, IsSet: true}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 8, IsSet: true}, @@ -1011,6 +1027,7 @@ var _ = Describe("Space Quotas", func() { TotalMemory: &types.NullInt{Value: 2048, IsSet: true}, InstanceMemory: &types.NullInt{Value: 1024, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 0, IsSet: false}, + TotalLogVolume: &types.NullInt{Value: 0, IsSet: false}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 0, IsSet: true}, @@ -1035,7 +1052,8 @@ var _ = Describe("Space Quotas", func() { "total_memory_in_mb": 2048, "per_process_memory_in_mb": 1024, "total_instances": null, - "per_app_tasks": null + "per_app_tasks": null, + "log_rate_limit_in_bytes_per_second": null }, "services": { "paid_services_allowed": true, @@ -1056,9 +1074,10 @@ var _ = Describe("Space Quotas", func() { expectedBody := map[string]interface{}{ "name": "elephant-trunk", "apps": map[string]interface{}{ - "total_memory_in_mb": 2048, - "per_process_memory_in_mb": 1024, - "total_instances": nil, + "total_memory_in_mb": 2048, + "per_process_memory_in_mb": 1024, + "total_instances": nil, + "log_rate_limit_in_bytes_per_second": nil, }, "services": map[string]interface{}{ "paid_services_allowed": true, @@ -1088,6 +1107,7 @@ var _ = Describe("Space Quotas", func() { TotalMemory: &types.NullInt{IsSet: true, Value: 2048}, InstanceMemory: &types.NullInt{IsSet: true, Value: 1024}, TotalAppInstances: &types.NullInt{IsSet: false, Value: 0}, + TotalLogVolume: &types.NullInt{IsSet: false, Value: 0}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{IsSet: true, Value: 0}, diff --git a/api/cloudcontroller/ccversion/minimum_version.go b/api/cloudcontroller/ccversion/minimum_version.go index 524f740604f..5158ab18f06 100644 --- a/api/cloudcontroller/ccversion/minimum_version.go +++ b/api/cloudcontroller/ccversion/minimum_version.go @@ -13,4 +13,6 @@ const ( MinVersionHTTP2RoutingV3 = "3.104.0" MinVersionSpaceSupporterV3 = "3.104.0" + + MinVersionLogRateLimitingV3 = "3.124.0" // TODO: update this when we have a CAPI release ) diff --git a/command/common/command_list_v7.go b/command/common/command_list_v7.go index 588e47e391f..3a2b660f3bd 100644 --- a/command/common/command_list_v7.go +++ b/command/common/command_list_v7.go @@ -134,7 +134,7 @@ type commandList struct { SSH v7.SSHCommand `command:"ssh" description:"SSH to an application container instance"` SSHCode v7.SSHCodeCommand `command:"ssh-code" description:"Get a one time password for ssh clients"` SSHEnabled v7.SSHEnabledCommand `command:"ssh-enabled" description:"Reports whether SSH is enabled on an application container instance"` - Scale v7.ScaleCommand `command:"scale" description:"Change or view the instance count, disk space limit, and memory limit for an app"` + Scale v7.ScaleCommand `command:"scale" description:"Change or view the instance count, disk space limit, memory limit, and log rate limit for an app"` SecurityGroup v7.SecurityGroupCommand `command:"security-group" description:"Show a single security group"` SecurityGroups v7.SecurityGroupsCommand `command:"security-groups" description:"List all security groups"` Service v7.ServiceCommand `command:"service" description:"Show service instance info"` diff --git a/command/flag/bytes_with_unlimited.go b/command/flag/bytes_with_unlimited.go new file mode 100644 index 00000000000..59becfb3394 --- /dev/null +++ b/command/flag/bytes_with_unlimited.go @@ -0,0 +1,59 @@ +package flag + +import ( + "regexp" + "strings" + + "code.cloudfoundry.org/bytefmt" + "code.cloudfoundry.org/cli/types" + flags "github.com/jessevdk/go-flags" +) + +type BytesWithUnlimited types.NullInt + +var zeroBytes *regexp.Regexp = regexp.MustCompile(`^0[KMGT]?B?$`) +var negativeOneBytes *regexp.Regexp = regexp.MustCompile(`^-1[KMGT]?B?$`) + +func (m *BytesWithUnlimited) UnmarshalFlag(val string) error { + if val == "" { + return nil + } + + if negativeOneBytes.MatchString(val) { + m.Value = -1 + m.IsSet = true + return nil + } + + if zeroBytes.MatchString(val) { + m.Value = 0 + m.IsSet = true + return nil + } + + size, err := ConvertToBytes(val) + if err != nil { + return err + } + + m.Value = int(size) + m.IsSet = true + + return nil +} + +func (m *BytesWithUnlimited) IsValidValue(val string) error { + return m.UnmarshalFlag(val) +} + +func ConvertToBytes(val string) (uint64, error) { + size, err := bytefmt.ToBytes(val) + + if err != nil || strings.Contains(strings.ToLower(val), ".") { + return size, &flags.Error{ + Type: flags.ErrRequired, + Message: `Byte quantity must be an integer with a unit of measurement like B, K, KB, M, MB, G, or GB`, + } + } + return size, nil +} diff --git a/command/flag/bytes_with_unlimited_test.go b/command/flag/bytes_with_unlimited_test.go new file mode 100644 index 00000000000..29cf00c2d79 --- /dev/null +++ b/command/flag/bytes_with_unlimited_test.go @@ -0,0 +1,148 @@ +package flag_test + +import ( + . "code.cloudfoundry.org/cli/command/flag" + flags "github.com/jessevdk/go-flags" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("BytesWithUnlimited", func() { + var bytesWithUnlimited BytesWithUnlimited + + Describe("UnmarshalFlag", func() { + BeforeEach(func() { + bytesWithUnlimited = BytesWithUnlimited{} + }) + + When("the suffix is B", func() { + It("interprets the number as bytes", func() { + err := bytesWithUnlimited.UnmarshalFlag("17B") + Expect(err).ToNot(HaveOccurred()) + Expect(bytesWithUnlimited.Value).To(BeEquivalentTo(17)) + }) + }) + + When("the suffix is K", func() { + It("interprets the number as kilobytes", func() { + err := bytesWithUnlimited.UnmarshalFlag("64K") + Expect(err).ToNot(HaveOccurred()) + Expect(bytesWithUnlimited.Value).To(BeEquivalentTo(64 * 1024)) + }) + }) + + When("the suffix is KB", func() { + It("interprets the number as kilobytes", func() { + err := bytesWithUnlimited.UnmarshalFlag("64KB") + Expect(err).ToNot(HaveOccurred()) + Expect(bytesWithUnlimited.Value).To(BeEquivalentTo(64 * 1024)) + }) + }) + + When("the suffix is M", func() { + It("interprets the number as megabytes", func() { + err := bytesWithUnlimited.UnmarshalFlag("17M") + Expect(err).ToNot(HaveOccurred()) + Expect(bytesWithUnlimited.Value).To(BeEquivalentTo(17 * 1024 * 1024)) + }) + }) + + When("the suffix is MB", func() { + It("interprets the number as megabytes", func() { + err := bytesWithUnlimited.UnmarshalFlag("19MB") + Expect(err).ToNot(HaveOccurred()) + Expect(bytesWithUnlimited.Value).To(BeEquivalentTo(19 * 1024 * 1024)) + }) + }) + + When("the suffix is G", func() { + It("interprets the number as gigabytes", func() { + err := bytesWithUnlimited.UnmarshalFlag("2G") + Expect(err).ToNot(HaveOccurred()) + Expect(bytesWithUnlimited.Value).To(BeEquivalentTo(2 * 1024 * 1024 * 1024)) + }) + }) + + When("the suffix is GB", func() { + It("interprets the number as gigabytes", func() { + err := bytesWithUnlimited.UnmarshalFlag("3GB") + Expect(err).ToNot(HaveOccurred()) + Expect(bytesWithUnlimited.Value).To(BeEquivalentTo(3 * 1024 * 1024 * 1024)) + }) + }) + + When("the value is -1 (unlimited)", func() { + It("interprets the number as -1 (unlimited)", func() { + err := bytesWithUnlimited.UnmarshalFlag("-1") + Expect(err).ToNot(HaveOccurred()) + Expect(bytesWithUnlimited.Value).To(BeEquivalentTo(-1)) + }) + + It("accepts units", func() { + err := bytesWithUnlimited.UnmarshalFlag("-1T") + Expect(err).ToNot(HaveOccurred()) + Expect(bytesWithUnlimited.Value).To(BeEquivalentTo(-1)) + }) + }) + + When("the value is 0", func() { + It("set's the value to 0", func() { + err := bytesWithUnlimited.UnmarshalFlag("0") + Expect(err).ToNot(HaveOccurred()) + Expect(bytesWithUnlimited.Value).To(BeEquivalentTo(0)) + }) + + It("accepts units", func() { + err := bytesWithUnlimited.UnmarshalFlag("0TB") + Expect(err).ToNot(HaveOccurred()) + Expect(bytesWithUnlimited.Value).To(BeEquivalentTo(0)) + }) + }) + + When("the suffix is lowercase", func() { + It("is case insensitive", func() { + err := bytesWithUnlimited.UnmarshalFlag("7m") + Expect(err).ToNot(HaveOccurred()) + Expect(bytesWithUnlimited.Value).To(BeEquivalentTo(7 * 1024 * 1024)) + }) + }) + + When("the value is invalid", func() { + It("returns an error", func() { + err := bytesWithUnlimited.UnmarshalFlag("invalid") + Expect(err).To(MatchError(&flags.Error{ + Type: flags.ErrRequired, + Message: `Byte quantity must be an integer with a unit of measurement like B, K, KB, M, MB, G, or GB`, + })) + }) + }) + + When("a decimal is used", func() { + It("returns an error", func() { + err := bytesWithUnlimited.UnmarshalFlag("1.2M") + Expect(err).To(MatchError(&flags.Error{ + Type: flags.ErrRequired, + Message: `Byte quantity must be an integer with a unit of measurement like B, K, KB, M, MB, G, or GB`, + })) + }) + }) + + When("the units are missing", func() { + It("returns an error", func() { + err := bytesWithUnlimited.UnmarshalFlag("37") + Expect(err).To(MatchError(&flags.Error{ + Type: flags.ErrRequired, + Message: `Byte quantity must be an integer with a unit of measurement like B, K, KB, M, MB, G, or GB`, + })) + }) + }) + + When("value is empty", func() { + It("sets IsSet to false", func() { + err := bytesWithUnlimited.UnmarshalFlag("") + Expect(err).NotTo(HaveOccurred()) + Expect(bytesWithUnlimited.IsSet).To(BeFalse()) + }) + }) + }) +}) diff --git a/command/flag/memory_with_unlimited.go b/command/flag/megabytes_with_unlimited.go similarity index 63% rename from command/flag/memory_with_unlimited.go rename to command/flag/megabytes_with_unlimited.go index 10fe06b32f6..de5595cc99a 100644 --- a/command/flag/memory_with_unlimited.go +++ b/command/flag/megabytes_with_unlimited.go @@ -4,9 +4,9 @@ import ( "code.cloudfoundry.org/cli/types" ) -type MemoryWithUnlimited types.NullInt +type MegabytesWithUnlimited types.NullInt -func (m *MemoryWithUnlimited) UnmarshalFlag(val string) error { +func (m *MegabytesWithUnlimited) UnmarshalFlag(val string) error { if val == "" { return nil } @@ -28,6 +28,6 @@ func (m *MemoryWithUnlimited) UnmarshalFlag(val string) error { return nil } -func (m *MemoryWithUnlimited) IsValidValue(val string) error { +func (m *MegabytesWithUnlimited) IsValidValue(val string) error { return m.UnmarshalFlag(val) } diff --git a/command/flag/memory_with_unlimited_test.go b/command/flag/megabytes_with_unlimited_test.go similarity index 58% rename from command/flag/memory_with_unlimited_test.go rename to command/flag/megabytes_with_unlimited_test.go index 65c4e92d939..3d47ba73e31 100644 --- a/command/flag/memory_with_unlimited_test.go +++ b/command/flag/megabytes_with_unlimited_test.go @@ -7,65 +7,65 @@ import ( . "github.com/onsi/gomega" ) -var _ = Describe("MemoryWithUnlimited", func() { - var memoryWithUnlimited MemoryWithUnlimited +var _ = Describe("MegabytesWithUnlimited", func() { + var megabytesWithUnlimited MegabytesWithUnlimited Describe("UnmarshalFlag", func() { BeforeEach(func() { - memoryWithUnlimited = MemoryWithUnlimited{} + megabytesWithUnlimited = MegabytesWithUnlimited{} }) When("the suffix is M", func() { - It("interprets the number as memoryWithUnlimited", func() { - err := memoryWithUnlimited.UnmarshalFlag("17M") + It("interprets the number as megabytesWithUnlimited", func() { + err := megabytesWithUnlimited.UnmarshalFlag("17M") Expect(err).ToNot(HaveOccurred()) - Expect(memoryWithUnlimited.Value).To(BeEquivalentTo(17)) + Expect(megabytesWithUnlimited.Value).To(BeEquivalentTo(17)) }) }) When("the suffix is MB", func() { - It("interprets the number as memoryWithUnlimited", func() { - err := memoryWithUnlimited.UnmarshalFlag("19MB") + It("interprets the number as megabytesWithUnlimited", func() { + err := megabytesWithUnlimited.UnmarshalFlag("19MB") Expect(err).ToNot(HaveOccurred()) - Expect(memoryWithUnlimited.Value).To(BeEquivalentTo(19)) + Expect(megabytesWithUnlimited.Value).To(BeEquivalentTo(19)) }) }) When("the suffix is G", func() { It("interprets the number as gigabytes", func() { - err := memoryWithUnlimited.UnmarshalFlag("2G") + err := megabytesWithUnlimited.UnmarshalFlag("2G") Expect(err).ToNot(HaveOccurred()) - Expect(memoryWithUnlimited.Value).To(BeEquivalentTo(2048)) + Expect(megabytesWithUnlimited.Value).To(BeEquivalentTo(2048)) }) }) When("the suffix is GB", func() { It("interprets the number as gigabytes", func() { - err := memoryWithUnlimited.UnmarshalFlag("3GB") + err := megabytesWithUnlimited.UnmarshalFlag("3GB") Expect(err).ToNot(HaveOccurred()) - Expect(memoryWithUnlimited.Value).To(BeEquivalentTo(3072)) + Expect(megabytesWithUnlimited.Value).To(BeEquivalentTo(3072)) }) }) When("the value is -1 (unlimited)", func() { - It("interprets the number as memoryWithUnlimited", func() { - err := memoryWithUnlimited.UnmarshalFlag("-1") + It("interprets the number as megabytesWithUnlimited", func() { + err := megabytesWithUnlimited.UnmarshalFlag("-1") Expect(err).ToNot(HaveOccurred()) - Expect(memoryWithUnlimited.Value).To(BeEquivalentTo(-1)) + Expect(megabytesWithUnlimited.Value).To(BeEquivalentTo(-1)) }) }) When("the suffix is lowercase", func() { It("is case insensitive", func() { - err := memoryWithUnlimited.UnmarshalFlag("7m") + err := megabytesWithUnlimited.UnmarshalFlag("7m") Expect(err).ToNot(HaveOccurred()) - Expect(memoryWithUnlimited.Value).To(BeEquivalentTo(7)) + Expect(megabytesWithUnlimited.Value).To(BeEquivalentTo(7)) }) }) - When("the memoryWithUnlimited are invalid", func() { + When("the megabytesWithUnlimited are invalid", func() { It("returns an error", func() { - err := memoryWithUnlimited.UnmarshalFlag("invalid") + err := megabytesWithUnlimited.UnmarshalFlag("invalid") Expect(err).To(MatchError(&flags.Error{ Type: flags.ErrRequired, Message: `Byte quantity must be an integer with a unit of measurement like M, MB, G, or GB`, @@ -75,7 +75,7 @@ var _ = Describe("MemoryWithUnlimited", func() { When("a decimal is used", func() { It("returns an error", func() { - err := memoryWithUnlimited.UnmarshalFlag("1.2M") + err := megabytesWithUnlimited.UnmarshalFlag("1.2M") Expect(err).To(MatchError(&flags.Error{ Type: flags.ErrRequired, Message: `Byte quantity must be an integer with a unit of measurement like M, MB, G, or GB`, @@ -85,7 +85,7 @@ var _ = Describe("MemoryWithUnlimited", func() { When("the units are missing", func() { It("returns an error", func() { - err := memoryWithUnlimited.UnmarshalFlag("37") + err := megabytesWithUnlimited.UnmarshalFlag("37") Expect(err).To(MatchError(&flags.Error{ Type: flags.ErrRequired, Message: `Byte quantity must be an integer with a unit of measurement like M, MB, G, or GB`, @@ -95,7 +95,7 @@ var _ = Describe("MemoryWithUnlimited", func() { When("the suffix is B", func() { It("returns an error", func() { - err := memoryWithUnlimited.UnmarshalFlag("10B") + err := megabytesWithUnlimited.UnmarshalFlag("10B") Expect(err).To(MatchError(&flags.Error{ Type: flags.ErrRequired, Message: `Byte quantity must be an integer with a unit of measurement like M, MB, G, or GB`, @@ -105,9 +105,9 @@ var _ = Describe("MemoryWithUnlimited", func() { When("value is empty", func() { It("sets IsSet to false", func() { - err := memoryWithUnlimited.UnmarshalFlag("") + err := megabytesWithUnlimited.UnmarshalFlag("") Expect(err).NotTo(HaveOccurred()) - Expect(memoryWithUnlimited.IsSet).To(BeFalse()) + Expect(megabytesWithUnlimited.IsSet).To(BeFalse()) }) }) }) diff --git a/command/v7/create_org_quota_command.go b/command/v7/create_org_quota_command.go index fe34a1de228..b4597e325aa 100644 --- a/command/v7/create_org_quota_command.go +++ b/command/v7/create_org_quota_command.go @@ -10,16 +10,18 @@ import ( type CreateOrgQuotaCommand struct { BaseCommand - RequiredArgs flag.OrganizationQuota `positional-args:"yes"` - NumAppInstances flag.IntegerLimit `short:"a" description:"Total number of application instances. (Default: unlimited)."` - PaidServicePlans bool `long:"allow-paid-service-plans" description:"Allow provisioning instances of paid service plans. (Default: disallowed)."` - PerProcessMemory flag.MemoryWithUnlimited `short:"i" description:"Maximum amount of memory a process can have (e.g. 1024M, 1G, 10G). (Default: unlimited)."` - TotalMemory flag.MemoryWithUnlimited `short:"m" description:"Total amount of memory all processes can have (e.g. 1024M, 1G, 10G). -1 represents an unlimited amount. (Default: 0)."` - TotalRoutes flag.IntegerLimit `short:"r" description:"Total number of routes. -1 represents an unlimited amount. (Default: 0)."` - TotalReservedPorts flag.IntegerLimit `long:"reserved-route-ports" description:"Maximum number of routes that may be created with ports. -1 represents an unlimited amount. (Default: 0)."` - TotalServiceInstances flag.IntegerLimit `short:"s" description:"Total number of service instances. -1 represents an unlimited amount. (Default: 0)."` - usage interface{} `usage:"CF_NAME create-org-quota ORG_QUOTA [-m TOTAL_MEMORY] [-i INSTANCE_MEMORY] [-r ROUTES] [-s SERVICE_INSTANCES] [-a APP_INSTANCES] [--allow-paid-service-plans] [--reserved-route-ports RESERVED_ROUTE_PORTS]"` - relatedCommands interface{} `related_commands:"create-org, org-quotas, set-org-quota"` + RequiredArgs flag.OrganizationQuota `positional-args:"yes"` + NumAppInstances flag.IntegerLimit `short:"a" description:"Total number of application instances. (Default: unlimited)."` + PaidServicePlans bool `long:"allow-paid-service-plans" description:"Allow provisioning instances of paid service plans. (Default: disallowed)."` + PerProcessMemory flag.MegabytesWithUnlimited `short:"i" description:"Maximum amount of memory a process can have (e.g. 1024M, 1G, 10G). (Default: unlimited)."` + TotalMemory flag.MegabytesWithUnlimited `short:"m" description:"Total amount of memory all processes can have (e.g. 1024M, 1G, 10G). -1 represents an unlimited amount. (Default: 0)."` + TotalRoutes flag.IntegerLimit `short:"r" description:"Total number of routes. -1 represents an unlimited amount. (Default: 0)."` + TotalReservedPorts flag.IntegerLimit `long:"reserved-route-ports" description:"Maximum number of routes that may be created with ports. -1 represents an unlimited amount. (Default: 0)."` + TotalServiceInstances flag.IntegerLimit `short:"s" description:"Total number of service instances. -1 represents an unlimited amount. (Default: 0)."` + TotalLogVolume flag.BytesWithUnlimited `short:"l" description:"Total log volume per second all processes can have, in bytes (e.g. 128B, 4K, 1M). -1 represents an unlimited amount. (Default: -1)."` + + usage interface{} `usage:"CF_NAME create-org-quota ORG_QUOTA [-m TOTAL_MEMORY] [-i INSTANCE_MEMORY] [-r ROUTES] [-s SERVICE_INSTANCES] [-a APP_INSTANCES] [--allow-paid-service-plans] [--reserved-route-ports RESERVED_ROUTE_PORTS] [-l LOG_VOLUME]"` + relatedCommands interface{} `related_commands:"create-org, org-quotas, set-org-quota"` } func (cmd CreateOrgQuotaCommand) Execute(args []string) error { @@ -49,6 +51,7 @@ func (cmd CreateOrgQuotaCommand) Execute(args []string) error { TotalServiceInstances: convertIntegerLimitFlagToNullInt(cmd.TotalServiceInstances), TotalRoutes: convertIntegerLimitFlagToNullInt(cmd.TotalRoutes), TotalReservedPorts: convertIntegerLimitFlagToNullInt(cmd.TotalReservedPorts), + TotalLogVolume: convertBytesFlagToNullInt(cmd.TotalLogVolume), }) cmd.UI.DisplayWarnings(warnings) @@ -66,7 +69,15 @@ func (cmd CreateOrgQuotaCommand) Execute(args []string) error { return nil } -func convertMegabytesFlagToNullInt(flag flag.MemoryWithUnlimited) *types.NullInt { +func convertBytesFlagToNullInt(flag flag.BytesWithUnlimited) *types.NullInt { + if !flag.IsSet { + return nil + } + + return &types.NullInt{IsSet: true, Value: flag.Value} +} + +func convertMegabytesFlagToNullInt(flag flag.MegabytesWithUnlimited) *types.NullInt { if !flag.IsSet { return nil } diff --git a/command/v7/create_org_quota_command_test.go b/command/v7/create_org_quota_command_test.go index d8f66f51fdd..c964bb964f2 100644 --- a/command/v7/create_org_quota_command_test.go +++ b/command/v7/create_org_quota_command_test.go @@ -52,7 +52,6 @@ var _ = Describe("create-org-quota Command", func() { }) JustBeforeEach(func() { - executeErr = cmd.Execute(nil) }) @@ -105,11 +104,12 @@ var _ = Describe("create-org-quota Command", func() { BeforeEach(func() { cmd.PaidServicePlans = true cmd.NumAppInstances = flag.IntegerLimit{IsSet: true, Value: 10} - cmd.PerProcessMemory = flag.MemoryWithUnlimited{IsSet: true, Value: 9} - cmd.TotalMemory = flag.MemoryWithUnlimited{IsSet: true, Value: 2048} + cmd.PerProcessMemory = flag.MegabytesWithUnlimited{IsSet: true, Value: 9} + cmd.TotalMemory = flag.MegabytesWithUnlimited{IsSet: true, Value: 2048} cmd.TotalRoutes = flag.IntegerLimit{IsSet: true, Value: 7} cmd.TotalReservedPorts = flag.IntegerLimit{IsSet: true, Value: 1} cmd.TotalServiceInstances = flag.IntegerLimit{IsSet: true, Value: 2} + cmd.TotalLogVolume = flag.BytesWithUnlimited{IsSet: true, Value: 8} fakeActor.CreateOrganizationQuotaReturns( v7action.Warnings{"warning"}, nil) @@ -142,6 +142,9 @@ var _ = Describe("create-org-quota Command", func() { Expect(quotaLimits.TotalServiceInstances.IsSet).To(Equal(true)) Expect(quotaLimits.TotalServiceInstances.Value).To(Equal(2)) + Expect(quotaLimits.TotalLogVolume.IsSet).To(Equal(true)) + Expect(quotaLimits.TotalLogVolume.Value).To(Equal(8)) + Expect(testUI.Out).To(Say("Creating org quota %s as bob...", orgQuotaName)) Expect(testUI.Out).To(Say("OK")) }) diff --git a/command/v7/create_space_quota_command.go b/command/v7/create_space_quota_command.go index 892d04675e7..250acde1844 100644 --- a/command/v7/create_space_quota_command.go +++ b/command/v7/create_space_quota_command.go @@ -9,16 +9,18 @@ import ( type CreateSpaceQuotaCommand struct { BaseCommand - RequiredArgs flag.SpaceQuota `positional-args:"yes"` - NumAppInstances flag.IntegerLimit `short:"a" description:"Total number of application instances. (Default: unlimited)."` - PaidServicePlans bool `long:"allow-paid-service-plans" description:"Allow provisioning instances of paid service plans. (Default: disallowed)."` - PerProcessMemory flag.MemoryWithUnlimited `short:"i" description:"Maximum amount of memory a process can have (e.g. 1024M, 1G, 10G). (Default: unlimited)."` - TotalMemory flag.MemoryWithUnlimited `short:"m" description:"Total amount of memory all processes can have (e.g. 1024M, 1G, 10G). -1 represents an unlimited amount. (Default: 0)."` - TotalRoutes flag.IntegerLimit `short:"r" description:"Total number of routes. -1 represents an unlimited amount. (Default: 0)."` - TotalReservedPorts flag.IntegerLimit `long:"reserved-route-ports" description:"Maximum number of routes that may be created with ports. -1 represents an unlimited amount. (Default: 0)."` - TotalServiceInstances flag.IntegerLimit `short:"s" description:"Total number of service instances. -1 represents an unlimited amount. (Default: 0)."` - usage interface{} `usage:"CF_NAME create-space-quota QUOTA [-m TOTAL_MEMORY] [-i INSTANCE_MEMORY] [-r ROUTES] [-s SERVICE_INSTANCES] [-a APP_INSTANCES] [--allow-paid-service-plans] [--reserved-route-ports RESERVED_ROUTE_PORTS]"` - relatedCommands interface{} `related_commands:"create-space, space-quotas, set-space-quota"` + RequiredArgs flag.SpaceQuota `positional-args:"yes"` + NumAppInstances flag.IntegerLimit `short:"a" description:"Total number of application instances. (Default: unlimited)."` + PaidServicePlans bool `long:"allow-paid-service-plans" description:"Allow provisioning instances of paid service plans. (Default: disallowed)."` + PerProcessMemory flag.MegabytesWithUnlimited `short:"i" description:"Maximum amount of memory a process can have (e.g. 1024M, 1G, 10G). (Default: unlimited)."` + TotalMemory flag.MegabytesWithUnlimited `short:"m" description:"Total amount of memory all processes can have (e.g. 1024M, 1G, 10G). -1 represents an unlimited amount. (Default: 0)."` + TotalRoutes flag.IntegerLimit `short:"r" description:"Total number of routes. -1 represents an unlimited amount. (Default: 0)."` + TotalReservedPorts flag.IntegerLimit `long:"reserved-route-ports" description:"Maximum number of routes that may be created with ports. -1 represents an unlimited amount. (Default: 0)."` + TotalServiceInstances flag.IntegerLimit `short:"s" description:"Total number of service instances. -1 represents an unlimited amount. (Default: 0)."` + TotalLogVolume flag.BytesWithUnlimited `short:"l" description:"Total log volume per second all processes can have, in bytes (e.g. 128B, 4K, 1M). -1 represents an unlimited amount. (Default: -1)."` + + usage interface{} `usage:"CF_NAME create-space-quota QUOTA [-m TOTAL_MEMORY] [-i INSTANCE_MEMORY] [-r ROUTES] [-s SERVICE_INSTANCES] [-a APP_INSTANCES] [--allow-paid-service-plans] [--reserved-route-ports RESERVED_ROUTE_PORTS] [-l LOG_VOLUME]"` + relatedCommands interface{} `related_commands:"create-space, space-quotas, set-space-quota"` } func (cmd CreateSpaceQuotaCommand) Execute([]string) error { @@ -49,6 +51,7 @@ func (cmd CreateSpaceQuotaCommand) Execute([]string) error { TotalServiceInstances: convertIntegerLimitFlagToNullInt(cmd.TotalServiceInstances), TotalRoutes: convertIntegerLimitFlagToNullInt(cmd.TotalRoutes), TotalReservedPorts: convertIntegerLimitFlagToNullInt(cmd.TotalReservedPorts), + TotalLogVolume: convertBytesFlagToNullInt(cmd.TotalLogVolume), }, ) diff --git a/command/v7/create_space_quota_command_test.go b/command/v7/create_space_quota_command_test.go index 6e94f2cb402..49f47c4a627 100644 --- a/command/v7/create_space_quota_command_test.go +++ b/command/v7/create_space_quota_command_test.go @@ -135,13 +135,14 @@ var _ = Describe("create-space-quota Command", func() { When("all flag limits are given", func() { BeforeEach(func() { - cmd.TotalMemory = flag.MemoryWithUnlimited{IsSet: true, Value: 47} - cmd.PerProcessMemory = flag.MemoryWithUnlimited{IsSet: true, Value: 23} + cmd.TotalMemory = flag.MegabytesWithUnlimited{IsSet: true, Value: 47} + cmd.PerProcessMemory = flag.MegabytesWithUnlimited{IsSet: true, Value: 23} cmd.NumAppInstances = flag.IntegerLimit{IsSet: true, Value: 4} cmd.PaidServicePlans = true cmd.TotalServiceInstances = flag.IntegerLimit{IsSet: true, Value: 9} cmd.TotalRoutes = flag.IntegerLimit{IsSet: true, Value: 1} cmd.TotalReservedPorts = flag.IntegerLimit{IsSet: true, Value: 7} + cmd.TotalLogVolume = flag.BytesWithUnlimited{IsSet: true, Value: 512} fakeActor.CreateSpaceQuotaReturns( v7action.Warnings{"warnings-1", "warnings-2"}, @@ -163,6 +164,7 @@ var _ = Describe("create-space-quota Command", func() { TotalServiceInstances: &types.NullInt{IsSet: true, Value: 9}, TotalRoutes: &types.NullInt{IsSet: true, Value: 1}, TotalReservedPorts: &types.NullInt{IsSet: true, Value: 7}, + TotalLogVolume: &types.NullInt{IsSet: true, Value: 512}, })) }) diff --git a/command/v7/org_quota_command_test.go b/command/v7/org_quota_command_test.go index 187fcda8d56..18d29c157c0 100644 --- a/command/v7/org_quota_command_test.go +++ b/command/v7/org_quota_command_test.go @@ -105,6 +105,7 @@ var _ = Describe("Org Quota Command", func() { TotalMemory: &types.NullInt{IsSet: true, Value: 2048}, InstanceMemory: &types.NullInt{IsSet: true, Value: 1024}, TotalAppInstances: &types.NullInt{IsSet: true, Value: 2}, + TotalLogVolume: &types.NullInt{IsSet: true, Value: 512}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{IsSet: false}, @@ -138,6 +139,7 @@ var _ = Describe("Org Quota Command", func() { Expect(testUI.Out).To(Say(`paid service plans:\s+disallowed`)) Expect(testUI.Out).To(Say(`app instances:\s+2`)) Expect(testUI.Out).To(Say(`route ports:\s+unlimited`)) + Expect(testUI.Out).To(Say(`log volume per second:\s+512B`)) }) }) }) diff --git a/command/v7/org_quotas_command_test.go b/command/v7/org_quotas_command_test.go index d69e632c6f0..e1d20bd4e09 100644 --- a/command/v7/org_quotas_command_test.go +++ b/command/v7/org_quotas_command_test.go @@ -66,6 +66,7 @@ var _ = Describe("org-quotas command", func() { TotalMemory: &types.NullInt{Value: 1048576, IsSet: true}, InstanceMemory: &types.NullInt{Value: 32, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 3, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: 512, IsSet: true}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 3, IsSet: true}, @@ -91,8 +92,8 @@ var _ = Describe("org-quotas command", func() { It("retrieves and displays all quotas", func() { Expect(executeErr).NotTo(HaveOccurred()) Expect(fakeActor.GetOrganizationQuotasCallCount()).To(Equal(1)) - Expect(testUI.Out).To(Say(`name\s+total memory\s+instance memory\s+routes\s+service instances\s+paid service plans\s+app instances\s+route ports`)) - Expect(testUI.Out).To(Say(`org-quota-1\s+1T\s+32M\s+5\s+3\s+allowed\s+3\s+2`)) + Expect(testUI.Out).To(Say(`name\s+total memory\s+instance memory\s+routes\s+service instances\s+paid service plans\s+app instances\s+route ports\s+log volume per second`)) + Expect(testUI.Out).To(Say(`org-quota-1\s+1T\s+32M\s+5\s+3\s+allowed\s+3\s+2\s+512B`)) }) When("there are limits that have not been configured", func() { @@ -105,6 +106,7 @@ var _ = Describe("org-quotas command", func() { TotalMemory: &types.NullInt{Value: 0, IsSet: false}, InstanceMemory: &types.NullInt{Value: 0, IsSet: false}, TotalAppInstances: &types.NullInt{Value: 0, IsSet: false}, + TotalLogVolume: &types.NullInt{Value: 0, IsSet: false}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 0, IsSet: false}, @@ -123,9 +125,8 @@ var _ = Describe("org-quotas command", func() { It("should convert default values from the API into readable outputs", func() { Expect(executeErr).NotTo(HaveOccurred()) - Expect(testUI.Out).To(Say(`name\s+total memory\s+instance memory\s+routes\s+service instances\s+paid service plans\s+app instances\s+route ports`)) - Expect(testUI.Out).To(Say(`default\s+unlimited\s+unlimited\s+unlimited\s+unlimited\s+allowed\s+unlimited\s+unlimited`)) - + Expect(testUI.Out).To(Say(`name\s+total memory\s+instance memory\s+routes\s+service instances\s+paid service plans\s+app instances\s+route ports\s+log volume per second`)) + Expect(testUI.Out).To(Say(`default\s+unlimited\s+unlimited\s+unlimited\s+unlimited\s+allowed\s+unlimited\s+unlimited\s+unlimited`)) }) }) }) diff --git a/command/v7/push_command.go b/command/v7/push_command.go index ea2e9175e48..4df28ebdec6 100644 --- a/command/v7/push_command.go +++ b/command/v7/push_command.go @@ -88,6 +88,7 @@ type PushCommand struct { HealthCheckHTTPEndpoint string `long:"endpoint" description:"Valid path on the app for an HTTP health check. Only used when specifying --health-check-type=http"` HealthCheckType flag.HealthCheckType `long:"health-check-type" short:"u" description:"Application health check type. Defaults to 'port'. 'http' requires a valid endpoint, for example, '/health'."` Instances flag.Instances `long:"instances" short:"i" description:"Number of instances"` + LogRateLimit string `long:"log-rate-limit" short:"l" description:"Log rate limit per second, in bytes (e.g. 128B, 4K, 1M). -l=-1 represents unlimited"` PathToManifest flag.ManifestPathWithExistenceCheck `long:"manifest" short:"f" description:"Path to manifest"` Memory string `long:"memory" short:"m" description:"Memory limit (e.g. 256M, 1024M, 1G)"` NoManifest bool `long:"no-manifest" description:"Ignore manifest file"` @@ -103,7 +104,7 @@ type PushCommand struct { Vars []template.VarKV `long:"var" description:"Variable key value pair for variable substitution, (e.g., name=app1); can specify multiple times"` PathsToVarsFiles []flag.PathWithExistenceCheck `long:"vars-file" description:"Path to a variable substitution file for manifest; can specify multiple times"` dockerPassword interface{} `environmentName:"CF_DOCKER_PASSWORD" environmentDescription:"Password used for private docker repository"` - usage interface{} `usage:"CF_NAME push APP_NAME [-b BUILDPACK_NAME]\n [-c COMMAND] [-f MANIFEST_PATH | --no-manifest] [--no-start] [--no-wait] [-i NUM_INSTANCES]\n [-k DISK] [-m MEMORY] [-p PATH] [-s STACK] [-t HEALTH_TIMEOUT] [--task TASK]\n [-u (process | port | http)] [--no-route | --random-route]\n [--var KEY=VALUE] [--vars-file VARS_FILE_PATH]...\n \n CF_NAME push APP_NAME --docker-image [REGISTRY_HOST:PORT/]IMAGE[:TAG] [--docker-username USERNAME]\n [-c COMMAND] [-f MANIFEST_PATH | --no-manifest] [--no-start] [--no-wait] [-i NUM_INSTANCES]\n [-k DISK] [-m MEMORY] [-p PATH] [-s STACK] [-t HEALTH_TIMEOUT] [--task TASK]\n [-u (process | port | http)] [--no-route | --random-route ]\n [--var KEY=VALUE] [--vars-file VARS_FILE_PATH]..."` + usage interface{} `usage:"CF_NAME push APP_NAME [-b BUILDPACK_NAME]\n [-c COMMAND] [-f MANIFEST_PATH | --no-manifest] [--no-start] [--no-wait] [-i NUM_INSTANCES]\n [-k DISK] [-m MEMORY] [-l LOG_RATE_LIMIT] [-p PATH] [-s STACK] [-t HEALTH_TIMEOUT] [--task TASK]\n [-u (process | port | http)] [--no-route | --random-route]\n [--var KEY=VALUE] [--vars-file VARS_FILE_PATH]...\n \n CF_NAME push APP_NAME --docker-image [REGISTRY_HOST:PORT/]IMAGE[:TAG] [--docker-username USERNAME]\n [-c COMMAND] [-f MANIFEST_PATH | --no-manifest] [--no-start] [--no-wait] [-i NUM_INSTANCES]\n [-k DISK] [-m MEMORY] [-l LOG_RATE_LIMIT] [-p PATH] [-s STACK] [-t HEALTH_TIMEOUT] [--task TASK]\n [-u (process | port | http)] [--no-route | --random-route ]\n [--var KEY=VALUE] [--vars-file VARS_FILE_PATH]..."` envCFStagingTimeout interface{} `environmentName:"CF_STAGING_TIMEOUT" environmentDescription:"Max wait time for staging, in minutes" environmentDefault:"15"` envCFStartupTimeout interface{} `environmentName:"CF_STARTUP_TIMEOUT" environmentDescription:"Max wait time for app instance startup, in minutes" environmentDefault:"5"` @@ -358,6 +359,7 @@ func (cmd PushCommand) GetFlagOverrides() (v7pushaction.FlagOverrides, error) { Vars: cmd.Vars, NoManifest: cmd.NoManifest, Task: cmd.Task, + LogRateLimit: cmd.LogRateLimit, }, nil } diff --git a/command/v7/push_command_test.go b/command/v7/push_command_test.go index 6d5d77fdcef..bedf00eedc0 100644 --- a/command/v7/push_command_test.go +++ b/command/v7/push_command_test.go @@ -319,7 +319,7 @@ var _ = Describe("push Command", func() { }) }) - When("marsahlling the manifest succeeds", func() { + When("marshalling the manifest succeeds", func() { BeforeEach(func() { fakeManifestParser.MarshalManifestReturns([]byte("our-manifest"), nil) }) @@ -1078,6 +1078,7 @@ var _ = Describe("push Command", func() { cmd.PathsToVarsFiles = []flag.PathWithExistenceCheck{"/vars1", "/vars2"} cmd.Vars = []template.VarKV{{Name: "key", Value: "val"}} cmd.Task = true + cmd.LogRateLimit = "512M" }) JustBeforeEach(func() { @@ -1106,6 +1107,7 @@ var _ = Describe("push Command", func() { Expect(overrides.PathsToVarsFiles).To(Equal([]string{"/vars1", "/vars2"})) Expect(overrides.Vars).To(Equal([]template.VarKV{{Name: "key", Value: "val"}})) Expect(overrides.Task).To(BeTrue()) + Expect(overrides.LogRateLimit).To(Equal("512M")) }) When("a docker image is provided", func() { diff --git a/command/v7/run_task_command.go b/command/v7/run_task_command.go index c01bbe2e243..eb07aa4d3f2 100644 --- a/command/v7/run_task_command.go +++ b/command/v7/run_task_command.go @@ -10,14 +10,15 @@ import ( type RunTaskCommand struct { BaseCommand - RequiredArgs flag.RunTaskArgsV7 `positional-args:"yes"` - Command string `long:"command" short:"c" description:"The command to execute"` - Disk flag.Megabytes `short:"k" description:"Disk limit (e.g. 256M, 1024M, 1G)"` - Memory flag.Megabytes `short:"m" description:"Memory limit (e.g. 256M, 1024M, 1G)"` - Name string `long:"name" description:"Name to give the task (generated if omitted)"` - Process string `long:"process" description:"Process type to use as a template for command, memory, and disk for the created task."` - usage interface{} `usage:"CF_NAME run-task APP_NAME [--command COMMAND] [-k DISK] [-m MEMORY] [--name TASK_NAME] [--process PROCESS_TYPE]\n\nTIP:\n Use 'cf logs' to display the logs of the app and all its tasks. If your task name is unique, grep this command's output for the task name to view task-specific logs.\n\nEXAMPLES:\n CF_NAME run-task my-app --command \"bundle exec rake db:migrate\" --name migrate\n\n CF_NAME run-task my-app --process batch_job\n\n CF_NAME run-task my-app"` - relatedCommands interface{} `related_commands:"logs, tasks, terminate-task"` + RequiredArgs flag.RunTaskArgsV7 `positional-args:"yes"` + Command string `long:"command" short:"c" description:"The command to execute"` + Disk flag.Megabytes `short:"k" description:"Disk limit (e.g. 256M, 1024M, 1G)"` + LogRateLimit flag.BytesWithUnlimited `short:"l" description:"Log rate limit per second, in bytes (e.g. 128B, 4K, 1M). -l=-1 represents unlimited"` + Memory flag.Megabytes `short:"m" description:"Memory limit (e.g. 256M, 1024M, 1G)"` + Name string `long:"name" description:"Name to give the task (generated if omitted)"` + Process string `long:"process" description:"Process type to use as a template for command, memory, and disk for the created task."` + usage interface{} `usage:"CF_NAME run-task APP_NAME [--command COMMAND] [-k DISK] [-m MEMORY] [-l LOG_RATE_LIMIT] [--name TASK_NAME] [--process PROCESS_TYPE]\n\nTIP:\n Use 'cf logs' to display the logs of the app and all its tasks. If your task name is unique, grep this command's output for the task name to view task-specific logs.\n\nEXAMPLES:\n CF_NAME run-task my-app --command \"bundle exec rake db:migrate\" --name migrate\n\n CF_NAME run-task my-app --process batch_job\n\n CF_NAME run-task my-app"` + relatedCommands interface{} `related_commands:"logs, tasks, terminate-task"` } func (cmd RunTaskCommand) Execute(args []string) error { @@ -59,6 +60,9 @@ func (cmd RunTaskCommand) Execute(args []string) error { if cmd.Memory.IsSet { inputTask.MemoryInMB = cmd.Memory.Value } + if cmd.LogRateLimit.IsSet { + inputTask.LogRateLimitInBPS = cmd.LogRateLimit.Value + } if cmd.Command == "" && cmd.Process == "" { cmd.Process = "task" } diff --git a/command/v7/run_task_command_test.go b/command/v7/run_task_command_test.go index 34233afe90b..585515345a7 100644 --- a/command/v7/run_task_command_test.go +++ b/command/v7/run_task_command_test.go @@ -197,6 +197,49 @@ var _ = Describe("run-task Command", func() { }) }) + When("task log rate limit is provided", func() { + BeforeEach(func() { + cmd.Name = "some-task-name" + cmd.LogRateLimit = flag.BytesWithUnlimited{Value: 1024 * 5, IsSet: true} + fakeActor.RunTaskReturns( + resources.Task{ + Name: "some-task-name", + SequenceID: 3, + }, + v7action.Warnings{"get-application-warning-3"}, + nil) + }) + + It("creates a new task and outputs all warnings", func() { + Expect(executeErr).ToNot(HaveOccurred()) + + Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1)) + appName, spaceGUID := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0) + Expect(appName).To(Equal("some-app-name")) + Expect(spaceGUID).To(Equal("some-space-guid")) + + Expect(fakeActor.RunTaskCallCount()).To(Equal(1)) + appGUID, task := fakeActor.RunTaskArgsForCall(0) + Expect(appGUID).To(Equal("some-app-guid")) + Expect(task).To(Equal(resources.Task{ + Command: "some command", + Name: "some-task-name", + LogRateLimitInBPS: 1024 * 5, + })) + + Expect(testUI.Out).To(Say("Creating task for app some-app-name in org some-org / space some-space as some-user...")) + Expect(testUI.Out).To(Say("Task has been submitted successfully for execution.")) + Expect(testUI.Out).To(Say("OK")) + + Expect(testUI.Out).To(Say(`task name:\s+some-task-name`)) + Expect(testUI.Out).To(Say(`task id:\s+3`)) + + Expect(testUI.Err).To(Say("get-application-warning-1")) + Expect(testUI.Err).To(Say("get-application-warning-2")) + Expect(testUI.Err).To(Say("get-application-warning-3")) + }) + }) + When("process is provided", func() { BeforeEach(func() { cmd.Name = "some-task-name" diff --git a/command/v7/scale_command.go b/command/v7/scale_command.go index fd0ed4f5469..99bda380f9f 100644 --- a/command/v7/scale_command.go +++ b/command/v7/scale_command.go @@ -7,20 +7,22 @@ import ( "code.cloudfoundry.org/cli/command/translatableerror" "code.cloudfoundry.org/cli/command/v7/shared" "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/types" ) type ScaleCommand struct { BaseCommand - RequiredArgs flag.AppName `positional-args:"yes"` - Force bool `long:"force" short:"f" description:"Force restart of app without prompt"` - Instances flag.Instances `long:"instances" short:"i" required:"false" description:"Number of instances"` - DiskLimit flag.Megabytes `short:"k" required:"false" description:"Disk limit (e.g. 256M, 1024M, 1G)"` - MemoryLimit flag.Megabytes `short:"m" required:"false" description:"Memory limit (e.g. 256M, 1024M, 1G)"` - ProcessType string `long:"process" default:"web" description:"App process to scale"` - usage interface{} `usage:"CF_NAME scale APP_NAME [--process PROCESS] [-i INSTANCES] [-k DISK] [-m MEMORY] [-f]\n\n Modifying the app's disk or memory will cause the app to restart."` - relatedCommands interface{} `related_commands:"push"` - envCFStartupTimeout interface{} `environmentName:"CF_STARTUP_TIMEOUT" environmentDescription:"Max wait time for app instance startup, in minutes" environmentDefault:"5"` + RequiredArgs flag.AppName `positional-args:"yes"` + Force bool `long:"force" short:"f" description:"Force restart of app without prompt"` + Instances flag.Instances `long:"instances" short:"i" required:"false" description:"Number of instances"` + DiskLimit flag.Megabytes `short:"k" required:"false" description:"Disk limit (e.g. 256M, 1024M, 1G)"` + LogRateLimit flag.BytesWithUnlimited `short:"l" required:"false" description:"Log rate limit per second, in bytes (e.g. 128B, 4K, 1M). -l=-1 represents unlimited"` + MemoryLimit flag.Megabytes `short:"m" required:"false" description:"Memory limit (e.g. 256M, 1024M, 1G)"` + ProcessType string `long:"process" default:"web" description:"App process to scale"` + usage interface{} `usage:"CF_NAME scale APP_NAME [--process PROCESS] [-i INSTANCES] [-k DISK] [-m MEMORY] [-l LOG_RATE_LIMIT] [-f]\n\n Modifying the app's disk, memory, or log rate will cause the app to restart."` + relatedCommands interface{} `related_commands:"push"` + envCFStartupTimeout interface{} `environmentName:"CF_STARTUP_TIMEOUT" environmentDescription:"Max wait time for app instance startup, in minutes" environmentDefault:"5"` } func (cmd ScaleCommand) Execute(args []string) error { @@ -40,7 +42,7 @@ func (cmd ScaleCommand) Execute(args []string) error { return err } - if !cmd.Instances.IsSet && !cmd.DiskLimit.IsSet && !cmd.MemoryLimit.IsSet { + if !cmd.Instances.IsSet && !cmd.DiskLimit.IsSet && !cmd.MemoryLimit.IsSet && !cmd.LogRateLimit.IsSet { return cmd.showCurrentScale(user.Name, err) } @@ -113,10 +115,11 @@ func (cmd ScaleCommand) scaleProcess(appGUID string, username string) (bool, err } warnings, err := cmd.Actor.ScaleProcessByApplication(appGUID, resources.Process{ - Type: cmd.ProcessType, - Instances: cmd.Instances.NullInt, - MemoryInMB: cmd.MemoryLimit.NullUint64, - DiskInMB: cmd.DiskLimit.NullUint64, + Type: cmd.ProcessType, + Instances: cmd.Instances.NullInt, + MemoryInMB: cmd.MemoryLimit.NullUint64, + DiskInMB: cmd.DiskLimit.NullUint64, + LogRateLimitInBPS: types.NullInt(cmd.LogRateLimit), }) cmd.UI.DisplayWarnings(warnings) if err != nil { @@ -203,5 +206,5 @@ func shouldShowCurrentScale(err error) bool { } func (cmd ScaleCommand) shouldRestart() bool { - return cmd.DiskLimit.IsSet || cmd.MemoryLimit.IsSet + return cmd.DiskLimit.IsSet || cmd.MemoryLimit.IsSet || cmd.LogRateLimit.IsSet } diff --git a/command/v7/scale_command_test.go b/command/v7/scale_command_test.go index 0286c41ebfe..92638290018 100644 --- a/command/v7/scale_command_test.go +++ b/command/v7/scale_command_test.go @@ -154,55 +154,65 @@ var _ = Describe("scale Command", func() { ProcessSummaries: v7action.ProcessSummaries{ { Process: resources.Process{ - Type: constant.ProcessTypeWeb, - MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, - DiskInMB: types.NullUint64{Value: 1024, IsSet: true}, + Type: constant.ProcessTypeWeb, + MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, + DiskInMB: types.NullUint64{Value: 1024, IsSet: true}, + LogRateLimitInBPS: types.NullInt{Value: 1024 * 10, IsSet: true}, }, InstanceDetails: []v7action.ProcessInstance{ v7action.ProcessInstance{ - Index: 0, - State: constant.ProcessInstanceRunning, - MemoryUsage: 1000000, - DiskUsage: 1000000, - MemoryQuota: 33554432, - DiskQuota: 2000000, - Uptime: time.Since(time.Unix(267321600, 0)), + Index: 0, + State: constant.ProcessInstanceRunning, + MemoryUsage: 1000000, + DiskUsage: 1000000, + LogRate: 1024 * 5, + MemoryQuota: 33554432, + DiskQuota: 2000000, + LogRateLimit: 1024 * 10, + Uptime: time.Since(time.Unix(267321600, 0)), }, v7action.ProcessInstance{ - Index: 1, - State: constant.ProcessInstanceRunning, - MemoryUsage: 2000000, - DiskUsage: 2000000, - MemoryQuota: 33554432, - DiskQuota: 4000000, - Uptime: time.Since(time.Unix(330480000, 0)), + Index: 1, + State: constant.ProcessInstanceRunning, + MemoryUsage: 2000000, + DiskUsage: 2000000, + LogRate: 1024 * 3, + MemoryQuota: 33554432, + DiskQuota: 4000000, + LogRateLimit: 1024 * 10, + Uptime: time.Since(time.Unix(330480000, 0)), }, v7action.ProcessInstance{ - Index: 2, - State: constant.ProcessInstanceRunning, - MemoryUsage: 3000000, - DiskUsage: 3000000, - MemoryQuota: 33554432, - DiskQuota: 6000000, - Uptime: time.Since(time.Unix(1277164800, 0)), + Index: 2, + State: constant.ProcessInstanceRunning, + MemoryUsage: 3000000, + DiskUsage: 3000000, + LogRate: 1024 * 4, + MemoryQuota: 33554432, + DiskQuota: 6000000, + LogRateLimit: 1024 * 10, + Uptime: time.Since(time.Unix(1277164800, 0)), }, }, }, { Process: resources.Process{ - Type: "console", - MemoryInMB: types.NullUint64{Value: 16, IsSet: true}, - DiskInMB: types.NullUint64{Value: 512, IsSet: true}, + Type: "console", + MemoryInMB: types.NullUint64{Value: 16, IsSet: true}, + DiskInMB: types.NullUint64{Value: 512, IsSet: true}, + LogRateLimitInBPS: types.NullInt{Value: 1024 * 5, IsSet: true}, }, InstanceDetails: []v7action.ProcessInstance{ v7action.ProcessInstance{ - Index: 0, - State: constant.ProcessInstanceRunning, - MemoryUsage: 1000000, - DiskUsage: 1000000, - MemoryQuota: 33554432, - DiskQuota: 8000000, - Uptime: time.Since(time.Unix(167572800, 0)), + Index: 0, + State: constant.ProcessInstanceRunning, + MemoryUsage: 1000000, + DiskUsage: 1000000, + LogRate: 1024, + MemoryQuota: 33554432, + DiskQuota: 8000000, + LogRateLimit: 1024 * 5, + Uptime: time.Since(time.Unix(167572800, 0)), }, }, }, @@ -241,14 +251,17 @@ var _ = Describe("scale Command", func() { Expect(webProcessSummary.Instances[0].Memory).To(Equal("976.6K of 32M")) Expect(webProcessSummary.Instances[0].Disk).To(Equal("976.6K of 1.9M")) Expect(webProcessSummary.Instances[0].CPU).To(Equal("0.0%")) + Expect(webProcessSummary.Instances[0].LogRate).To(Equal("5K/s of 10K/s")) Expect(webProcessSummary.Instances[1].Memory).To(Equal("1.9M of 32M")) Expect(webProcessSummary.Instances[1].Disk).To(Equal("1.9M of 3.8M")) Expect(webProcessSummary.Instances[1].CPU).To(Equal("0.0%")) + Expect(webProcessSummary.Instances[1].LogRate).To(Equal("3K/s of 10K/s")) Expect(webProcessSummary.Instances[2].Memory).To(Equal("2.9M of 32M")) Expect(webProcessSummary.Instances[2].Disk).To(Equal("2.9M of 5.7M")) Expect(webProcessSummary.Instances[2].CPU).To(Equal("0.0%")) + Expect(webProcessSummary.Instances[2].LogRate).To(Equal("4K/s of 10K/s")) consoleProcessSummary := firstAppTable.Processes[1] Expect(consoleProcessSummary.Type).To(Equal("console")) @@ -258,6 +271,7 @@ var _ = Describe("scale Command", func() { Expect(consoleProcessSummary.Instances[0].Memory).To(Equal("976.6K of 32M")) Expect(consoleProcessSummary.Instances[0].Disk).To(Equal("976.6K of 7.6M")) Expect(consoleProcessSummary.Instances[0].CPU).To(Equal("0.0%")) + Expect(consoleProcessSummary.Instances[0].LogRate).To(Equal("1K/s of 5K/s")) Expect(testUI.Err).To(Say("get-app-warning")) Expect(testUI.Err).To(Say("get-app-summary-warning")) @@ -292,6 +306,8 @@ var _ = Describe("scale Command", func() { cmd.DiskLimit.IsSet = true cmd.MemoryLimit.Value = 100 cmd.MemoryLimit.IsSet = true + cmd.LogRateLimit.Value = 1024 + cmd.LogRateLimit.IsSet = true fakeActor.ScaleProcessByApplicationReturns( v7action.Warnings{"scale-warning"}, nil) @@ -407,14 +423,17 @@ var _ = Describe("scale Command", func() { Expect(webProcessSummary.Instances[0].Memory).To(Equal("976.6K of 32M")) Expect(webProcessSummary.Instances[0].Disk).To(Equal("976.6K of 1.9M")) Expect(webProcessSummary.Instances[0].CPU).To(Equal("0.0%")) + Expect(webProcessSummary.Instances[0].LogRate).To(Equal("5K/s of 10K/s")) Expect(webProcessSummary.Instances[1].Memory).To(Equal("1.9M of 32M")) Expect(webProcessSummary.Instances[1].Disk).To(Equal("1.9M of 3.8M")) Expect(webProcessSummary.Instances[1].CPU).To(Equal("0.0%")) + Expect(webProcessSummary.Instances[1].LogRate).To(Equal("3K/s of 10K/s")) Expect(webProcessSummary.Instances[2].Memory).To(Equal("2.9M of 32M")) Expect(webProcessSummary.Instances[2].Disk).To(Equal("2.9M of 5.7M")) Expect(webProcessSummary.Instances[2].CPU).To(Equal("0.0%")) + Expect(webProcessSummary.Instances[2].LogRate).To(Equal("4K/s of 10K/s")) consoleProcessSummary := firstAppTable.Processes[1] Expect(consoleProcessSummary.Type).To(Equal("console")) @@ -424,6 +443,7 @@ var _ = Describe("scale Command", func() { Expect(consoleProcessSummary.Instances[0].Memory).To(Equal("976.6K of 32M")) Expect(consoleProcessSummary.Instances[0].Disk).To(Equal("976.6K of 7.6M")) Expect(consoleProcessSummary.Instances[0].CPU).To(Equal("0.0%")) + Expect(consoleProcessSummary.Instances[0].LogRate).To(Equal("1K/s of 5K/s")) Expect(testUI.Err).To(Say("get-app-warning")) Expect(testUI.Err).To(Say("scale-warning")) @@ -440,10 +460,11 @@ var _ = Describe("scale Command", func() { appGUIDArg, scaleProcess := fakeActor.ScaleProcessByApplicationArgsForCall(0) Expect(appGUIDArg).To(Equal("some-app-guid")) Expect(scaleProcess).To(Equal(resources.Process{ - Type: constant.ProcessTypeWeb, - Instances: types.NullInt{Value: 2, IsSet: true}, - DiskInMB: types.NullUint64{Value: 50, IsSet: true}, - MemoryInMB: types.NullUint64{Value: 100, IsSet: true}, + Type: constant.ProcessTypeWeb, + Instances: types.NullInt{Value: 2, IsSet: true}, + DiskInMB: types.NullUint64{Value: 50, IsSet: true}, + MemoryInMB: types.NullUint64{Value: 100, IsSet: true}, + LogRateLimitInBPS: types.NullInt{Value: 1024, IsSet: true}, })) Expect(fakeActor.StopApplicationCallCount()).To(Equal(1)) @@ -752,6 +773,59 @@ var _ = Describe("scale Command", func() { }) }) + When("only the log rate limit option is provided", func() { + BeforeEach(func() { + cmd.LogRateLimit.Value = 2048 + cmd.LogRateLimit.IsSet = true + fakeActor.ScaleProcessByApplicationReturns( + v7action.Warnings{"scale-warning"}, + nil) + fakeActor.GetDetailedAppSummaryReturns( + appSummary, + v7action.Warnings{"get-instances-warning"}, + nil) + + _, err := input.Write([]byte("y\n")) + Expect(err).ToNot(HaveOccurred()) + }) + + It("scales, restarts, and displays scale properties", func() { + Expect(executeErr).ToNot(HaveOccurred()) + + Expect(testUI.Out).To(Say("Scaling")) + Expect(testUI.Out).To(Say("This will cause the app to restart")) + Expect(testUI.Out).To(Say("Stopping")) + Expect(testUI.Out).To(Say("Starting")) + + Expect(testUI.Err).To(Say("get-app-warning")) + Expect(testUI.Err).To(Say("scale-warning")) + Expect(testUI.Err).To(Say("get-instances-warning")) + + Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1)) + appNameArg, spaceGUIDArg := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0) + Expect(appNameArg).To(Equal(app.Name)) + Expect(spaceGUIDArg).To(Equal("some-space-guid")) + + Expect(fakeActor.ScaleProcessByApplicationCallCount()).To(Equal(1)) + appGUIDArg, scaleProcess := fakeActor.ScaleProcessByApplicationArgsForCall(0) + Expect(appGUIDArg).To(Equal("some-app-guid")) + Expect(scaleProcess).To(Equal(resources.Process{ + Type: constant.ProcessTypeWeb, + LogRateLimitInBPS: types.NullInt{Value: 2048, IsSet: true}, + })) + + Expect(fakeActor.StopApplicationCallCount()).To(Equal(1)) + appGUID := fakeActor.StopApplicationArgsForCall(0) + Expect(appGUID).To(Equal("some-app-guid")) + + Expect(fakeActor.StartApplicationCallCount()).To(Equal(1)) + appGUID = fakeActor.StartApplicationArgsForCall(0) + Expect(appGUID).To(Equal("some-app-guid")) + + Expect(fakeActor.GetDetailedAppSummaryCallCount()).To(Equal(1)) + }) + }) + When("an error is encountered scaling the application", func() { var expectedErr error diff --git a/command/v7/shared/app_summary_displayer.go b/command/v7/shared/app_summary_displayer.go index 38978ee148d..e9c5b41a759 100644 --- a/command/v7/shared/app_summary_displayer.go +++ b/command/v7/shared/app_summary_displayer.go @@ -72,6 +72,14 @@ func routeSummary(rs []resources.Route) string { return strings.Join(formattedRoutes, ", ") } +func formatLogRateLimit(limit int64) string { + if limit == -1 { + return "unlimited" + } else { + return bytefmt.ByteSize(uint64(limit)) + "/s" + } +} + func (display AppSummaryDisplayer) displayAppInstancesTable(processSummary v7action.ProcessSummary) { table := [][]string{ { @@ -81,6 +89,7 @@ func (display AppSummaryDisplayer) displayAppInstancesTable(processSummary v7act display.UI.TranslateText("cpu"), display.UI.TranslateText("memory"), display.UI.TranslateText("disk"), + display.UI.TranslateText("logging"), display.UI.TranslateText("details"), }, } @@ -99,6 +108,10 @@ func (display AppSummaryDisplayer) displayAppInstancesTable(processSummary v7act "DiskUsage": bytefmt.ByteSize(instance.DiskUsage), "DiskQuota": bytefmt.ByteSize(instance.DiskQuota), }), + display.UI.TranslateText("{{.LogRate}}/s of {{.LogRateLimit}}", map[string]interface{}{ + "LogRate": bytefmt.ByteSize(instance.LogRate), + "LogRateLimit": formatLogRateLimit(instance.LogRateLimit), + }), instance.Details, }) } diff --git a/command/v7/shared/app_summary_displayer_test.go b/command/v7/shared/app_summary_displayer_test.go index d35d31af5cf..1ba958be041 100644 --- a/command/v7/shared/app_summary_displayer_test.go +++ b/command/v7/shared/app_summary_displayer_test.go @@ -16,6 +16,9 @@ import ( ) var _ = Describe("app summary displayer", func() { + + const instanceStatsTitles = `state\s+since\s+cpu\s+memory\s+disk\s+logging\s+details` + var ( appSummaryDisplayer *AppSummaryDisplayer output *Buffer @@ -54,59 +57,69 @@ var _ = Describe("app summary displayer", func() { ProcessSummaries: v7action.ProcessSummaries{ { Process: resources.Process{ - Type: constant.ProcessTypeWeb, - MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, - DiskInMB: types.NullUint64{Value: 1024, IsSet: true}, + Type: constant.ProcessTypeWeb, + MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, + DiskInMB: types.NullUint64{Value: 1024, IsSet: true}, + LogRateLimitInBPS: types.NullInt{Value: 1024 * 5, IsSet: true}, }, Sidecars: []resources.Sidecar{}, InstanceDetails: []v7action.ProcessInstance{ v7action.ProcessInstance{ - Index: 0, - State: constant.ProcessInstanceRunning, - MemoryUsage: 1000000, - DiskUsage: 1000000, - MemoryQuota: 33554432, - DiskQuota: 2000000, - Uptime: uptime, - Details: "Some Details 1", + Index: 0, + State: constant.ProcessInstanceRunning, + MemoryUsage: 1000000, + DiskUsage: 1000000, + LogRate: 1024, + MemoryQuota: 33554432, + DiskQuota: 2000000, + LogRateLimit: 1024 * 5, + Uptime: uptime, + Details: "Some Details 1", }, v7action.ProcessInstance{ - Index: 1, - State: constant.ProcessInstanceRunning, - MemoryUsage: 2000000, - DiskUsage: 2000000, - MemoryQuota: 33554432, - DiskQuota: 4000000, - Uptime: time.Since(time.Unix(330480000, 0)), - Details: "Some Details 2", + Index: 1, + State: constant.ProcessInstanceRunning, + MemoryUsage: 2000000, + DiskUsage: 2000000, + LogRate: 1024 * 2, + MemoryQuota: 33554432, + DiskQuota: 4000000, + LogRateLimit: 1024 * 5, + Uptime: time.Since(time.Unix(330480000, 0)), + Details: "Some Details 2", }, v7action.ProcessInstance{ - Index: 2, - State: constant.ProcessInstanceRunning, - MemoryUsage: 3000000, - DiskUsage: 3000000, - MemoryQuota: 33554432, - DiskQuota: 6000000, - Uptime: time.Since(time.Unix(1277164800, 0)), + Index: 2, + State: constant.ProcessInstanceRunning, + MemoryUsage: 3000000, + DiskUsage: 3000000, + LogRate: 1024 * 3, + MemoryQuota: 33554432, + DiskQuota: 6000000, + LogRateLimit: 1024 * 5, + Uptime: time.Since(time.Unix(1277164800, 0)), }, }, }, { Process: resources.Process{ - Type: "console", - MemoryInMB: types.NullUint64{Value: 16, IsSet: true}, - DiskInMB: types.NullUint64{Value: 512, IsSet: true}, + Type: "console", + MemoryInMB: types.NullUint64{Value: 16, IsSet: true}, + DiskInMB: types.NullUint64{Value: 512, IsSet: true}, + LogRateLimitInBPS: types.NullInt{Value: 256, IsSet: true}, }, Sidecars: []resources.Sidecar{}, InstanceDetails: []v7action.ProcessInstance{ v7action.ProcessInstance{ - Index: 0, - State: constant.ProcessInstanceRunning, - MemoryUsage: 1000000, - DiskUsage: 1000000, - MemoryQuota: 33554432, - DiskQuota: 8000000, - Uptime: time.Since(time.Unix(167572800, 0)), + Index: 0, + State: constant.ProcessInstanceRunning, + MemoryUsage: 1000000, + DiskUsage: 1000000, + LogRate: 128, + MemoryQuota: 33554432, + DiskQuota: 8000000, + LogRateLimit: 256, + Uptime: time.Since(time.Unix(167572800, 0)), }, }, }, @@ -130,16 +143,19 @@ var _ = Describe("app summary displayer", func() { Expect(time.Parse(time.RFC3339, webProcessSummary.Instances[0].Since)).To(BeTemporally("~", time.Now().Add(-uptime), 2*time.Second)) Expect(webProcessSummary.Instances[0].Disk).To(Equal("976.6K of 1.9M")) Expect(webProcessSummary.Instances[0].CPU).To(Equal("0.0%")) + Expect(webProcessSummary.Instances[0].LogRate).To(Equal("1K/s of 5K/s")) Expect(webProcessSummary.Instances[0].Details).To(Equal("Some Details 1")) Expect(webProcessSummary.Instances[1].Memory).To(Equal("1.9M of 32M")) Expect(webProcessSummary.Instances[1].Disk).To(Equal("1.9M of 3.8M")) Expect(webProcessSummary.Instances[1].CPU).To(Equal("0.0%")) + Expect(webProcessSummary.Instances[1].LogRate).To(Equal("2K/s of 5K/s")) Expect(webProcessSummary.Instances[1].Details).To(Equal("Some Details 2")) Expect(webProcessSummary.Instances[2].Memory).To(Equal("2.9M of 32M")) Expect(webProcessSummary.Instances[2].Disk).To(Equal("2.9M of 5.7M")) Expect(webProcessSummary.Instances[2].CPU).To(Equal("0.0%")) + Expect(webProcessSummary.Instances[2].LogRate).To(Equal("3K/s of 5K/s")) consoleProcessSummary := processTable.Processes[1] Expect(consoleProcessSummary.Type).To(Equal("console")) @@ -150,6 +166,45 @@ var _ = Describe("app summary displayer", func() { Expect(consoleProcessSummary.Instances[0].Memory).To(Equal("976.6K of 32M")) Expect(consoleProcessSummary.Instances[0].Disk).To(Equal("976.6K of 7.6M")) Expect(consoleProcessSummary.Instances[0].CPU).To(Equal("0.0%")) + Expect(consoleProcessSummary.Instances[0].LogRate).To(Equal("128B/s of 256B/s")) + }) + }) + + When("the log rate is unlimited", func() { + BeforeEach(func() { + summary = v7action.DetailedApplicationSummary{ + ApplicationSummary: v7action.ApplicationSummary{ + Application: resources.Application{ + GUID: "some-app-guid", + State: constant.ApplicationStarted, + }, + ProcessSummaries: v7action.ProcessSummaries{ + { + Process: resources.Process{ + Type: constant.ProcessTypeWeb, + MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, + DiskInMB: types.NullUint64{Value: 1024, IsSet: true}, + }, + Sidecars: []resources.Sidecar{}, + InstanceDetails: []v7action.ProcessInstance{ + v7action.ProcessInstance{ + Index: 0, + State: constant.ProcessInstanceRunning, + LogRate: 1024, + LogRateLimit: -1, + }, + }, + }, + }, + }, + } + }) + + It("renders unlimited log rate limits correctly", func() { + processTable := helpers.ParseV3AppProcessTable(output.Contents()) + webProcessSummary := processTable.Processes[0] + + Expect(webProcessSummary.Instances[0].LogRate).To(Equal("1K/s of unlimited")) }) }) @@ -197,7 +252,7 @@ var _ = Describe("app summary displayer", func() { It("lists instance stats for process types that have > 0 instances", func() { Expect(testUI.Out).To(Say(`type:\s+web`)) Expect(testUI.Out).To(Say(`sidecars: `)) - Expect(testUI.Out).To(Say(`state\s+since\s+cpu\s+memory\s+disk\s+details`)) + Expect(testUI.Out).To(Say(instanceStatsTitles)) }) It("does not show the instance stats table for process types with 0 instances", func() { @@ -227,7 +282,7 @@ var _ = Describe("app summary displayer", func() { It("displays the instances table", func() { Expect(testUI.Out).To(Say(`type:\s+web`)) Expect(testUI.Out).To(Say(`sidecars: `)) - Expect(testUI.Out).To(Say(`state\s+since\s+cpu\s+memory\s+disk\s+details`)) + Expect(testUI.Out).To(Say(instanceStatsTitles)) }) }) @@ -342,7 +397,7 @@ var _ = Describe("app summary displayer", func() { }) It("does not display the instance table", func() { - Expect(testUI.Out).NotTo(Say(`state\s+since\s+cpu\s+memory\s+disk\s+details`)) + Expect(testUI.Out).NotTo(Say(instanceStatsTitles)) }) }) @@ -380,7 +435,7 @@ var _ = Describe("app summary displayer", func() { }) It("does not display the instance table", func() { - Expect(testUI.Out).NotTo(Say(`state\s+since\s+cpu\s+memory\s+disk\s+details`)) + Expect(testUI.Out).NotTo(Say(instanceStatsTitles)) }) }) @@ -421,7 +476,7 @@ var _ = Describe("app summary displayer", func() { }) It("does not display the instance table", func() { - Expect(testUI.Out).NotTo(Say(`state\s+since\s+cpu\s+memory\s+disk\s+details`)) + Expect(testUI.Out).NotTo(Say(instanceStatsTitles)) }) }) diff --git a/command/v7/shared/quota_displayer.go b/command/v7/shared/quota_displayer.go index d209223b18c..bcb84ddc973 100644 --- a/command/v7/shared/quota_displayer.go +++ b/command/v7/shared/quota_displayer.go @@ -12,7 +12,8 @@ import ( ) const ( - MEGABYTE = 1024 * 1024 + KILOBYTE = 1024 + MEGABYTE = 1024 * KILOBYTE GIGABYTE = 1024 * MEGABYTE TERABYTE = 1024 * GIGABYTE ) @@ -32,7 +33,7 @@ func (displayer QuotaDisplayer) DisplayQuotasTable(quotas []resources.Quota, emp } var keyValueTable = [][]string{ - {"name", "total memory", "instance memory", "routes", "service instances", "paid service plans", "app instances", "route ports"}, + {"name", "total memory", "instance memory", "routes", "service instances", "paid service plans", "app instances", "route ports", "log volume per second"}, } for _, quota := range quotas { @@ -45,6 +46,7 @@ func (displayer QuotaDisplayer) DisplayQuotasTable(quotas []resources.Quota, emp displayer.presentBooleanValue(*quota.Services.PaidServicePlans), displayer.presentQuotaValue(*quota.Apps.TotalAppInstances), displayer.presentQuotaValue(*quota.Routes.TotalReservedPorts), + displayer.presentQuotaBytesValue(*quota.Apps.TotalLogVolume), }) } @@ -60,6 +62,7 @@ func (displayer QuotaDisplayer) DisplaySingleQuota(quota resources.Quota) { {displayer.ui.TranslateText("paid service plans:"), displayer.presentBooleanValue(*quota.Services.PaidServicePlans)}, {displayer.ui.TranslateText("app instances:"), displayer.presentQuotaValue(*quota.Apps.TotalAppInstances)}, {displayer.ui.TranslateText("route ports:"), displayer.presentQuotaValue(*quota.Routes.TotalReservedPorts)}, + {displayer.ui.TranslateText("log volume per second:"), displayer.presentQuotaBytesValue(*quota.Apps.TotalLogVolume)}, } displayer.ui.DisplayKeyValueTable("", quotaTable, 3) @@ -81,6 +84,14 @@ func (displayer QuotaDisplayer) presentQuotaValue(limit types.NullInt) string { } } +func (displayer QuotaDisplayer) presentQuotaBytesValue(limit types.NullInt) string { + if !limit.IsSet { + return "unlimited" + } else { + return addMemoryUnits(float64(limit.Value)) + } +} + func (displayer QuotaDisplayer) presentQuotaMemoryValue(limit types.NullInt) string { if !limit.IsSet { return "unlimited" @@ -103,6 +114,11 @@ func addMemoryUnits(bytes float64) string { case bytes >= MEGABYTE: unit = "M" value /= MEGABYTE + case bytes >= KILOBYTE: + unit = "K" + value /= KILOBYTE + case bytes >= 1: + unit = "B" case bytes == 0: return "0" } diff --git a/command/v7/space_quota_command_test.go b/command/v7/space_quota_command_test.go index ce15a9c9fc4..20952d63888 100644 --- a/command/v7/space_quota_command_test.go +++ b/command/v7/space_quota_command_test.go @@ -102,6 +102,7 @@ var _ = Describe("Space Quota Command", func() { TotalMemory: &types.NullInt{IsSet: true, Value: 2048}, InstanceMemory: &types.NullInt{IsSet: true, Value: 1024}, TotalAppInstances: &types.NullInt{IsSet: true, Value: 2}, + TotalLogVolume: &types.NullInt{IsSet: true, Value: 512}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{IsSet: false}, @@ -135,6 +136,7 @@ var _ = Describe("Space Quota Command", func() { Expect(testUI.Out).To(Say(`paid service plans:\s+disallowed`)) Expect(testUI.Out).To(Say(`app instances:\s+2`)) Expect(testUI.Out).To(Say(`route ports:\s+unlimited`)) + Expect(testUI.Out).To(Say(`log volume per second:\s+512B`)) }) }) }) diff --git a/command/v7/space_quotas_command_test.go b/command/v7/space_quotas_command_test.go index c0626293045..268b6dd9cc0 100644 --- a/command/v7/space_quotas_command_test.go +++ b/command/v7/space_quotas_command_test.go @@ -69,6 +69,7 @@ var _ = Describe("space-quotas command", func() { TotalMemory: &types.NullInt{Value: 1048576, IsSet: true}, InstanceMemory: &types.NullInt{Value: 32, IsSet: true}, TotalAppInstances: &types.NullInt{Value: 3, IsSet: true}, + TotalLogVolume: &types.NullInt{Value: 512, IsSet: true}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 3, IsSet: true}, @@ -98,8 +99,8 @@ var _ = Describe("space-quotas command", func() { orgGUID := fakeActor.GetSpaceQuotasByOrgGUIDArgsForCall(0) Expect(orgGUID).To(Equal(fakeConfig.TargetedOrganization().GUID)) - Expect(testUI.Out).To(Say(`name\s+total memory\s+instance memory\s+routes\s+service instances\s+paid service plans\s+app instances\s+route ports`)) - Expect(testUI.Out).To(Say(`space-quota-1\s+1T\s+32M\s+5\s+3\s+allowed\s+3\s+2`)) + Expect(testUI.Out).To(Say(`name\s+total memory\s+instance memory\s+routes\s+service instances\s+paid service plans\s+app instances\s+route ports\s+log volume per second`)) + Expect(testUI.Out).To(Say(`space-quota-1\s+1T\s+32M\s+5\s+3\s+allowed\s+3\s+2\s+512B`)) }) When("there are limits that have not been configured", func() { @@ -112,6 +113,7 @@ var _ = Describe("space-quotas command", func() { TotalMemory: &types.NullInt{Value: 0, IsSet: false}, InstanceMemory: &types.NullInt{Value: 0, IsSet: false}, TotalAppInstances: &types.NullInt{Value: 0, IsSet: false}, + TotalLogVolume: &types.NullInt{Value: 0, IsSet: false}, }, Services: resources.ServiceLimit{ TotalServiceInstances: &types.NullInt{Value: 0, IsSet: false}, @@ -130,8 +132,8 @@ var _ = Describe("space-quotas command", func() { It("should convert default values from the API into readable outputs", func() { Expect(executeErr).NotTo(HaveOccurred()) - Expect(testUI.Out).To(Say(`name\s+total memory\s+instance memory\s+routes\s+service instances\s+paid service plans\s+app instances\s+route ports`)) - Expect(testUI.Out).To(Say(`default\s+unlimited\s+unlimited\s+unlimited\s+unlimited\s+allowed\s+unlimited\s+unlimited`)) + Expect(testUI.Out).To(Say(`name\s+total memory\s+instance memory\s+routes\s+service instances\s+paid service plans\s+app instances\s+route ports\s+log volume per second`)) + Expect(testUI.Out).To(Say(`default\s+unlimited\s+unlimited\s+unlimited\s+unlimited\s+allowed\s+unlimited\s+unlimited\s+unlimited`)) }) }) diff --git a/command/v7/update_org_quota_command.go b/command/v7/update_org_quota_command.go index 04a93c6a7b8..70124cfc201 100644 --- a/command/v7/update_org_quota_command.go +++ b/command/v7/update_org_quota_command.go @@ -9,18 +9,20 @@ import ( type UpdateOrgQuotaCommand struct { BaseCommand - RequiredArgs flag.OrganizationQuota `positional-args:"Yes"` - NumAppInstances flag.IntegerLimit `short:"a" description:"Total number of application instances. -1 represents an unlimited amount."` - PaidServicePlans bool `long:"allow-paid-service-plans" description:"Allow provisioning instances of paid service plans."` - NoPaidServicePlans bool `long:"disallow-paid-service-plans" description:"Disallow provisioning instances of paid service plans."` - PerProcessMemory flag.MemoryWithUnlimited `short:"i" description:"Maximum amount of memory a process can have (e.g. 1024M, 1G, 10G). -1 represents an unlimited amount."` - TotalMemory flag.MemoryWithUnlimited `short:"m" description:"Total amount of memory all processes can have (e.g. 1024M, 1G, 10G). -1 represents an unlimited amount."` - NewName string `short:"n" description:"New name"` - TotalRoutes flag.IntegerLimit `short:"r" description:"Total number of routes. -1 represents an unlimited amount."` - TotalReservedPorts flag.IntegerLimit `long:"reserved-route-ports" description:"Maximum number of routes that may be created with ports. -1 represents an unlimited amount."` - TotalServiceInstances flag.IntegerLimit `short:"s" description:"Total number of service instances. -1 represents an unlimited amount."` - usage interface{} `usage:"CF_NAME update-org-quota QUOTA [-m TOTAL_MEMORY] [-i INSTANCE_MEMORY] [-n NEW_NAME] [-r ROUTES] [-s SERVICE_INSTANCES] [-a APP_INSTANCES] [--allow-paid-service-plans | --disallow-paid-service-plans] [--reserved-route-ports RESERVED_ROUTE_PORTS]"` - relatedCommands interface{} `related_commands:"org, org-quota"` + RequiredArgs flag.OrganizationQuota `positional-args:"Yes"` + NumAppInstances flag.IntegerLimit `short:"a" description:"Total number of application instances. -1 represents an unlimited amount."` + PaidServicePlans bool `long:"allow-paid-service-plans" description:"Allow provisioning instances of paid service plans."` + NoPaidServicePlans bool `long:"disallow-paid-service-plans" description:"Disallow provisioning instances of paid service plans."` + PerProcessMemory flag.MegabytesWithUnlimited `short:"i" description:"Maximum amount of memory a process can have (e.g. 1024M, 1G, 10G). -1 represents an unlimited amount."` + TotalMemory flag.MegabytesWithUnlimited `short:"m" description:"Total amount of memory all processes can have (e.g. 1024M, 1G, 10G). -1 represents an unlimited amount."` + NewName string `short:"n" description:"New name"` + TotalRoutes flag.IntegerLimit `short:"r" description:"Total number of routes. -1 represents an unlimited amount."` + TotalReservedPorts flag.IntegerLimit `long:"reserved-route-ports" description:"Maximum number of routes that may be created with ports. -1 represents an unlimited amount."` + TotalServiceInstances flag.IntegerLimit `short:"s" description:"Total number of service instances. -1 represents an unlimited amount."` + TotalLogVolume flag.BytesWithUnlimited `short:"l" description:"Total log volume per second all processes can have, in bytes (e.g. 128B, 4K, 1M). -1 represents an unlimited amount."` + + usage interface{} `usage:"CF_NAME update-org-quota QUOTA [-m TOTAL_MEMORY] [-i INSTANCE_MEMORY] [-n NEW_NAME] [-r ROUTES] [-s SERVICE_INSTANCES] [-a APP_INSTANCES] [--allow-paid-service-plans | --disallow-paid-service-plans] [--reserved-route-ports RESERVED_ROUTE_PORTS] [-l LOG_VOLUME]"` + relatedCommands interface{} `related_commands:"org, org-quota"` } func (cmd UpdateOrgQuotaCommand) Execute(args []string) error { @@ -61,6 +63,7 @@ func (cmd UpdateOrgQuotaCommand) Execute(args []string) error { TotalServiceInstances: convertIntegerLimitFlagToNullInt(cmd.TotalServiceInstances), TotalRoutes: convertIntegerLimitFlagToNullInt(cmd.TotalRoutes), TotalReservedPorts: convertIntegerLimitFlagToNullInt(cmd.TotalReservedPorts), + TotalLogVolume: convertBytesFlagToNullInt(cmd.TotalLogVolume), } warnings, err := cmd.Actor.UpdateOrganizationQuota(oldQuotaName, cmd.NewName, updatedQuotaLimits) diff --git a/command/v7/update_org_quota_command_test.go b/command/v7/update_org_quota_command_test.go index 4dd534d5dc2..d5b9e2253d9 100644 --- a/command/v7/update_org_quota_command_test.go +++ b/command/v7/update_org_quota_command_test.go @@ -91,11 +91,12 @@ var _ = Describe("UpdateOrgQuotaCommand", func() { cmd.NewName = "new-org-quota-name" cmd.PaidServicePlans = true cmd.NumAppInstances = flag.IntegerLimit{IsSet: true, Value: 10} - cmd.PerProcessMemory = flag.MemoryWithUnlimited{IsSet: true, Value: 9} - cmd.TotalMemory = flag.MemoryWithUnlimited{IsSet: true, Value: 2048} + cmd.PerProcessMemory = flag.MegabytesWithUnlimited{IsSet: true, Value: 9} + cmd.TotalMemory = flag.MegabytesWithUnlimited{IsSet: true, Value: 2048} cmd.TotalRoutes = flag.IntegerLimit{IsSet: true, Value: 7} cmd.TotalReservedPorts = flag.IntegerLimit{IsSet: true, Value: 1} cmd.TotalServiceInstances = flag.IntegerLimit{IsSet: true, Value: 2} + cmd.TotalLogVolume = flag.BytesWithUnlimited{IsSet: true, Value: 8} fakeActor.UpdateOrganizationQuotaReturns( v7action.Warnings{"warning"}, nil) @@ -130,6 +131,9 @@ var _ = Describe("UpdateOrgQuotaCommand", func() { Expect(quotaLimits.TotalServiceInstances.IsSet).To(Equal(true)) Expect(quotaLimits.TotalServiceInstances.Value).To(Equal(2)) + Expect(quotaLimits.TotalLogVolume.IsSet).To(Equal(true)) + Expect(quotaLimits.TotalLogVolume.Value).To(Equal(8)) + Expect(testUI.Out).To(Say("Updating org quota %s as bob...", orgQuotaName)) Expect(testUI.Out).To(Say("OK")) }) @@ -137,7 +141,7 @@ var _ = Describe("UpdateOrgQuotaCommand", func() { When("only some org quota limits are updated", func() { BeforeEach(func() { - cmd.TotalMemory = flag.MemoryWithUnlimited{IsSet: true, Value: 2048} + cmd.TotalMemory = flag.MegabytesWithUnlimited{IsSet: true, Value: 2048} cmd.TotalServiceInstances = flag.IntegerLimit{IsSet: true, Value: 2} fakeActor.UpdateOrganizationQuotaReturns( v7action.Warnings{"warning"}, @@ -169,6 +173,8 @@ var _ = Describe("UpdateOrgQuotaCommand", func() { Expect(quotaLimits.TotalReservedPorts).To(BeNil()) + Expect(quotaLimits.TotalLogVolume).To(BeNil()) + Expect(testUI.Out).To(Say("Updating org quota %s as bob...", orgQuotaName)) Expect(testUI.Out).To(Say("OK")) }) diff --git a/command/v7/update_space_quota_command.go b/command/v7/update_space_quota_command.go index c2905ecae64..300645c44eb 100644 --- a/command/v7/update_space_quota_command.go +++ b/command/v7/update_space_quota_command.go @@ -9,18 +9,20 @@ import ( type UpdateSpaceQuotaCommand struct { BaseCommand - RequiredArgs flag.SpaceQuota `positional-args:"Yes"` - NumAppInstances flag.IntegerLimit `short:"a" description:"Total number of application instances. -1 represents an unlimited amount."` - PaidServicePlans bool `long:"allow-paid-service-plans" description:"Allow provisioning instances of paid service plans."` - NoPaidServicePlans bool `long:"disallow-paid-service-plans" description:"Disallow provisioning instances of paid service plans."` - PerProcessMemory flag.MemoryWithUnlimited `short:"i" description:"Maximum amount of memory a process can have (e.g. 1024M, 1G, 10G). -1 represents an unlimited amount."` - TotalMemory flag.MemoryWithUnlimited `short:"m" description:"Total amount of memory all processes can have (e.g. 1024M, 1G, 10G). -1 represents an unlimited amount."` - NewName string `short:"n" description:"New name"` - TotalRoutes flag.IntegerLimit `short:"r" description:"Total number of routes. -1 represents an unlimited amount."` - TotalReservedPorts flag.IntegerLimit `long:"reserved-route-ports" description:"Maximum number of routes that may be created with ports. -1 represents an unlimited amount."` - TotalServiceInstances flag.IntegerLimit `short:"s" description:"Total number of service instances. -1 represents an unlimited amount."` - usage interface{} `usage:"CF_NAME update-space-quota QUOTA [-m TOTAL_MEMORY] [-i INSTANCE_MEMORY] [-n NEW_NAME] [-r ROUTES] [-s SERVICE_INSTANCES] [-a APP_INSTANCES] [--allow-paid-service-plans | --disallow-paid-service-plans] [--reserved-route-ports RESERVED_ROUTE_PORTS]"` - relatedCommands interface{} `related_commands:"space, space-quota, space-quotas"` + RequiredArgs flag.SpaceQuota `positional-args:"Yes"` + NumAppInstances flag.IntegerLimit `short:"a" description:"Total number of application instances. -1 represents an unlimited amount."` + PaidServicePlans bool `long:"allow-paid-service-plans" description:"Allow provisioning instances of paid service plans."` + NoPaidServicePlans bool `long:"disallow-paid-service-plans" description:"Disallow provisioning instances of paid service plans."` + PerProcessMemory flag.MegabytesWithUnlimited `short:"i" description:"Maximum amount of memory a process can have (e.g. 1024M, 1G, 10G). -1 represents an unlimited amount."` + TotalMemory flag.MegabytesWithUnlimited `short:"m" description:"Total amount of memory all processes can have (e.g. 1024M, 1G, 10G). -1 represents an unlimited amount."` + NewName string `short:"n" description:"New name"` + TotalRoutes flag.IntegerLimit `short:"r" description:"Total number of routes. -1 represents an unlimited amount."` + TotalReservedPorts flag.IntegerLimit `long:"reserved-route-ports" description:"Maximum number of routes that may be created with ports. -1 represents an unlimited amount."` + TotalServiceInstances flag.IntegerLimit `short:"s" description:"Total number of service instances. -1 represents an unlimited amount."` + TotalLogVolume flag.BytesWithUnlimited `short:"l" description:"Total log volume per second all processes can have, in bytes (e.g. 128B, 4K, 1M). -1 represents an unlimited amount."` + + usage interface{} `usage:"CF_NAME update-space-quota QUOTA [-m TOTAL_MEMORY] [-i INSTANCE_MEMORY] [-n NEW_NAME] [-r ROUTES] [-s SERVICE_INSTANCES] [-a APP_INSTANCES] [--allow-paid-service-plans | --disallow-paid-service-plans] [--reserved-route-ports RESERVED_ROUTE_PORTS] [-l LOG_VOLUME]"` + relatedCommands interface{} `related_commands:"space, space-quota, space-quotas"` } func (cmd UpdateSpaceQuotaCommand) Execute(args []string) error { @@ -63,6 +65,7 @@ func (cmd UpdateSpaceQuotaCommand) Execute(args []string) error { TotalServiceInstances: convertIntegerLimitFlagToNullInt(cmd.TotalServiceInstances), TotalRoutes: convertIntegerLimitFlagToNullInt(cmd.TotalRoutes), TotalReservedPorts: convertIntegerLimitFlagToNullInt(cmd.TotalReservedPorts), + TotalLogVolume: convertBytesFlagToNullInt(cmd.TotalLogVolume), } warnings, err := cmd.Actor.UpdateSpaceQuota(oldQuotaName, orgGUID, cmd.NewName, updatedQuotaLimits) diff --git a/command/v7/update_space_quota_command_test.go b/command/v7/update_space_quota_command_test.go index 2caf0945a62..42a7b8079b3 100644 --- a/command/v7/update_space_quota_command_test.go +++ b/command/v7/update_space_quota_command_test.go @@ -94,11 +94,12 @@ var _ = Describe("UpdateSpaceQuotaCommand", func() { cmd.NewName = "new-space-quota-name" cmd.PaidServicePlans = true cmd.NumAppInstances = flag.IntegerLimit{IsSet: true, Value: 10} - cmd.PerProcessMemory = flag.MemoryWithUnlimited{IsSet: true, Value: 9} - cmd.TotalMemory = flag.MemoryWithUnlimited{IsSet: true, Value: 2048} + cmd.PerProcessMemory = flag.MegabytesWithUnlimited{IsSet: true, Value: 9} + cmd.TotalMemory = flag.MegabytesWithUnlimited{IsSet: true, Value: 2048} cmd.TotalRoutes = flag.IntegerLimit{IsSet: true, Value: 7} cmd.TotalReservedPorts = flag.IntegerLimit{IsSet: true, Value: 1} cmd.TotalServiceInstances = flag.IntegerLimit{IsSet: true, Value: 2} + cmd.TotalLogVolume = flag.BytesWithUnlimited{IsSet: true, Value: 512} fakeActor.UpdateSpaceQuotaReturns( v7action.Warnings{"warning"}, nil) @@ -134,6 +135,9 @@ var _ = Describe("UpdateSpaceQuotaCommand", func() { Expect(quotaLimits.TotalServiceInstances.IsSet).To(Equal(true)) Expect(quotaLimits.TotalServiceInstances.Value).To(Equal(2)) + Expect(quotaLimits.TotalLogVolume.IsSet).To(Equal(true)) + Expect(quotaLimits.TotalLogVolume.Value).To(Equal(512)) + Expect(testUI.Out).To(Say("Updating space quota %s for org %s as bob...", spaceQuotaName, orgName)) Expect(testUI.Out).To(Say("OK")) }) @@ -141,7 +145,7 @@ var _ = Describe("UpdateSpaceQuotaCommand", func() { When("only some org quota limits are updated", func() { BeforeEach(func() { - cmd.TotalMemory = flag.MemoryWithUnlimited{IsSet: true, Value: 2048} + cmd.TotalMemory = flag.MegabytesWithUnlimited{IsSet: true, Value: 2048} cmd.TotalServiceInstances = flag.IntegerLimit{IsSet: true, Value: 2} fakeActor.UpdateSpaceQuotaReturns( v7action.Warnings{"warning"}, @@ -174,6 +178,8 @@ var _ = Describe("UpdateSpaceQuotaCommand", func() { Expect(quotaLimits.TotalReservedPorts).To(BeNil()) + Expect(quotaLimits.TotalLogVolume).To(BeNil()) + Expect(testUI.Out).To(Say("Updating space quota %s for org %s as bob...", spaceQuotaName, orgName)) Expect(testUI.Out).To(Say("OK")) }) diff --git a/integration/helpers/app.go b/integration/helpers/app.go index 92cccfa3902..963fa464d31 100644 --- a/integration/helpers/app.go +++ b/integration/helpers/app.go @@ -369,3 +369,17 @@ func WaitForAppDiskToTakeEffect(appName string, processIndex int, instanceIndex return appTable.Processes[processIndex].Instances[instanceIndex].Disk }).Should(MatchRegexp(fmt.Sprintf(`\d+(\.\d+)?[KMG]? of %s`, expectedDisk))) } + +func WaitForLogRateLimitToTakeEffect(appName string, processIndex int, instanceIndex int, shouldRestartFirst bool, expectedLogRateLimit string) { + if shouldRestartFirst { + session := CF("restart", appName) + Eventually(session).Should(Exit(0)) + } + + Eventually(func() string { + session := CF("app", appName) + Eventually(session).Should(Exit(0)) + appTable := ParseV3AppProcessTable(session.Out.Contents()) + return appTable.Processes[processIndex].Instances[instanceIndex].LogRate + }).Should(MatchRegexp(fmt.Sprintf(`\d+(\.\d+)?[KMG]?/s of %s/s`, expectedLogRateLimit))) +} diff --git a/integration/helpers/app_instance_table.go b/integration/helpers/app_instance_table.go index 440d8b91bcf..57964f11261 100644 --- a/integration/helpers/app_instance_table.go +++ b/integration/helpers/app_instance_table.go @@ -14,6 +14,7 @@ type AppInstanceRow struct { CPU string Memory string Disk string + LogRate string Details string } @@ -55,11 +56,13 @@ func ParseV3AppProcessTable(input []byte) AppTable { switch { case strings.HasPrefix(row, "#"): + const columnCount = 8 + // instance row columns := splitColumns(row) details := "" - if len(columns) >= 7 { - details = columns[6] + if len(columns) >= columnCount { + details = columns[7] } instanceRow := AppInstanceRow{ @@ -69,6 +72,7 @@ func ParseV3AppProcessTable(input []byte) AppTable { CPU: columns[3], Memory: columns[4], Disk: columns[5], + LogRate: columns[6], Details: details, } lastProcessIndex := len(appTable.Processes) - 1 diff --git a/integration/helpers/app_instance_table_test.go b/integration/helpers/app_instance_table_test.go index 31fc921e530..6ae03a086a4 100644 --- a/integration/helpers/app_instance_table_test.go +++ b/integration/helpers/app_instance_table_test.go @@ -21,17 +21,17 @@ buildpacks: ruby 1.6.44 type: web instances: 4/4 memory usage: 32M - state since cpu memory disk -#0 running 2017-08-02 17:12:10 PM 0.0% 21.2M of 32M 84.5M of 1G -#1 running 2017-08-03 09:39:25 AM 0.2% 19.3M of 32M 84.5M of 1G -#2 running 2017-08-03 03:29:25 AM 0.1% 22.8M of 32M 84.5M of 1G -#3 running 2017-08-02 17:12:10 PM 0.2% 22.9M of 32M 84.5M of 1G + state since cpu memory disk logging +#0 running 2017-08-02 17:12:10 PM 0.0% 21.2M of 32M 84.5M of 1G 5B/s of 1K/s +#1 running 2017-08-03 09:39:25 AM 0.2% 19.3M of 32M 84.5M of 1G 7B/s of 1K/s +#2 running 2017-08-03 03:29:25 AM 0.1% 22.8M of 32M 84.5M of 1G 10B/s of 1K/s +#3 running 2017-08-02 17:12:10 PM 0.2% 22.9M of 32M 84.5M of 1G 8B/s of 1K/s type: worker instances: 1/1 memory usage: 32M - state since cpu memory disk -#0 stopped 2017-08-02 17:12:10 PM 0.0% 0M of 32M 0M of 1G + state since cpu memory disk logging +#0 stopped 2017-08-02 17:12:10 PM 0.0% 0M of 32M 0M of 1G 0B/s of 1K/s ` appInstanceTable := ParseV3AppProcessTable([]byte(input)) Expect(appInstanceTable).To(Equal(AppTable{ @@ -41,10 +41,10 @@ memory usage: 32M InstanceCount: "4/4", MemUsage: "32M", Instances: []AppInstanceRow{ - {Index: "#0", State: "running", Since: "2017-08-02 17:12:10 PM", CPU: "0.0%", Memory: "21.2M of 32M", Disk: "84.5M of 1G"}, - {Index: "#1", State: "running", Since: "2017-08-03 09:39:25 AM", CPU: "0.2%", Memory: "19.3M of 32M", Disk: "84.5M of 1G"}, - {Index: "#2", State: "running", Since: "2017-08-03 03:29:25 AM", CPU: "0.1%", Memory: "22.8M of 32M", Disk: "84.5M of 1G"}, - {Index: "#3", State: "running", Since: "2017-08-02 17:12:10 PM", CPU: "0.2%", Memory: "22.9M of 32M", Disk: "84.5M of 1G"}, + {Index: "#0", State: "running", Since: "2017-08-02 17:12:10 PM", CPU: "0.0%", Memory: "21.2M of 32M", Disk: "84.5M of 1G", LogRate: "5B/s of 1K/s"}, + {Index: "#1", State: "running", Since: "2017-08-03 09:39:25 AM", CPU: "0.2%", Memory: "19.3M of 32M", Disk: "84.5M of 1G", LogRate: "7B/s of 1K/s"}, + {Index: "#2", State: "running", Since: "2017-08-03 03:29:25 AM", CPU: "0.1%", Memory: "22.8M of 32M", Disk: "84.5M of 1G", LogRate: "10B/s of 1K/s"}, + {Index: "#3", State: "running", Since: "2017-08-02 17:12:10 PM", CPU: "0.2%", Memory: "22.9M of 32M", Disk: "84.5M of 1G", LogRate: "8B/s of 1K/s"}, }, }, { @@ -52,7 +52,7 @@ memory usage: 32M InstanceCount: "1/1", MemUsage: "32M", Instances: []AppInstanceRow{ - {Index: "#0", State: "stopped", Since: "2017-08-02 17:12:10 PM", CPU: "0.0%", Memory: "0M of 32M", Disk: "0M of 1G"}, + {Index: "#0", State: "stopped", Since: "2017-08-02 17:12:10 PM", CPU: "0.0%", Memory: "0M of 32M", Disk: "0M of 1G", LogRate: "0B/s of 1K/s"}, }, }, }, @@ -66,11 +66,11 @@ Showing health and status for app dora in org wut / space wut as admin... type: web instances: 4/4 memory usage: 32M - state since cpu memory disk -#0 running 2017-08-02 17:12:10 PM 0.0% 21.2M of 32M 84.5M of 1G -#1 running 2017-08-03 09:39:25 AM 0.2% 19.3M of 32M 84.5M of 1G -#2 running 2017-08-03 03:29:25 AM 0.1% 22.8M of 32M 84.5M of 1G -#3 running 2017-08-02 17:12:10 PM 0.2% 22.9M of 32M 84.5M of 1G + state since cpu memory disk logging +#0 running 2017-08-02 17:12:10 PM 0.0% 21.2M of 32M 84.5M of 1G 1.3K/s of 5K/s +#1 running 2017-08-03 09:39:25 AM 0.2% 19.3M of 32M 84.5M of 1G 1.2K/s of 5K/s +#2 running 2017-08-03 03:29:25 AM 0.1% 22.8M of 32M 84.5M of 1G 1.1K/s of 5K/s +#3 running 2017-08-02 17:12:10 PM 0.2% 22.9M of 32M 84.5M of 1G 1.2K/s of 5K/s ` appInstanceTable := ParseV3AppProcessTable([]byte(input)) Expect(appInstanceTable).To(Equal(AppTable{ @@ -80,10 +80,10 @@ memory usage: 32M InstanceCount: "4/4", MemUsage: "32M", Instances: []AppInstanceRow{ - {Index: "#0", State: "running", Since: "2017-08-02 17:12:10 PM", CPU: "0.0%", Memory: "21.2M of 32M", Disk: "84.5M of 1G"}, - {Index: "#1", State: "running", Since: "2017-08-03 09:39:25 AM", CPU: "0.2%", Memory: "19.3M of 32M", Disk: "84.5M of 1G"}, - {Index: "#2", State: "running", Since: "2017-08-03 03:29:25 AM", CPU: "0.1%", Memory: "22.8M of 32M", Disk: "84.5M of 1G"}, - {Index: "#3", State: "running", Since: "2017-08-02 17:12:10 PM", CPU: "0.2%", Memory: "22.9M of 32M", Disk: "84.5M of 1G"}, + {Index: "#0", State: "running", Since: "2017-08-02 17:12:10 PM", CPU: "0.0%", Memory: "21.2M of 32M", Disk: "84.5M of 1G", LogRate: "1.3K/s of 5K/s"}, + {Index: "#1", State: "running", Since: "2017-08-03 09:39:25 AM", CPU: "0.2%", Memory: "19.3M of 32M", Disk: "84.5M of 1G", LogRate: "1.2K/s of 5K/s"}, + {Index: "#2", State: "running", Since: "2017-08-03 03:29:25 AM", CPU: "0.1%", Memory: "22.8M of 32M", Disk: "84.5M of 1G", LogRate: "1.1K/s of 5K/s"}, + {Index: "#3", State: "running", Since: "2017-08-02 17:12:10 PM", CPU: "0.2%", Memory: "22.9M of 32M", Disk: "84.5M of 1G", LogRate: "1.2K/s of 5K/s"}, }, }, }, diff --git a/integration/v7/global/org_quota_command_test.go b/integration/v7/global/org_quota_command_test.go index 7161c979982..ccd33cde2ba 100644 --- a/integration/v7/global/org_quota_command_test.go +++ b/integration/v7/global/org_quota_command_test.go @@ -70,6 +70,7 @@ var _ = Describe("org-quota command", func() { Eventually(session).Should(Say(`paid service plans:\s+allowed`)) Eventually(session).Should(Say(`app instances:\s+unlimited`)) Eventually(session).Should(Say(`route ports:\s+100`)) + Eventually(session).Should(Say(`log volume per second:\s+unlimited`)) Eventually(session).Should(Exit(0)) }) diff --git a/integration/v7/global/org_quotas_command_test.go b/integration/v7/global/org_quotas_command_test.go index f264c4ea438..4327504b7b5 100644 --- a/integration/v7/global/org_quotas_command_test.go +++ b/integration/v7/global/org_quotas_command_test.go @@ -60,8 +60,8 @@ var _ = Describe("org-quotas command", func() { It("lists the org quotas", func() { session := helpers.CF("org-quotas") - Eventually(session).Should(Say(`name\s+total memory\s+instance memory\s+routes\s+service instances\s+paid service plans\s+app instances\s+route ports`)) - Eventually(session).Should(Say(`%s\s+%s\s+%s\s+%s\s+%s\s+%s\s+%s\s+%s`, quotaName, totalMemory, instanceMemory, routes, serviceInstances, "allowed", appInstances, reservedRoutePorts)) + Eventually(session).Should(Say(`name\s+total memory\s+instance memory\s+routes\s+service instances\s+paid service plans\s+app instances\s+route ports\s+log volume per second`)) + Eventually(session).Should(Say(`%s\s+%s\s+%s\s+%s\s+%s\s+%s\s+%s\s+%s\s+%s`, quotaName, totalMemory, instanceMemory, routes, serviceInstances, "allowed", appInstances, reservedRoutePorts, "unlimited")) Eventually(session).Should(Exit(0)) }) }) diff --git a/integration/v7/isolated/app_command_test.go b/integration/v7/isolated/app_command_test.go index 7eed60c44ce..4c91a401b56 100644 --- a/integration/v7/isolated/app_command_test.go +++ b/integration/v7/isolated/app_command_test.go @@ -131,7 +131,7 @@ applications: Eventually(session).Should(Say(`type:\s+web`)) Eventually(session).Should(Say(`instances:\s+\d/2`)) Eventually(session).Should(Say(`memory usage:\s+128M`)) - Eventually(session).Should(Say(`\s+state\s+since\s+cpu\s+memory\s+disk\s+details`)) + Eventually(session).Should(Say(`\s+state\s+since\s+cpu\s+memory\s+disk\s+logging\s+details`)) Eventually(session).Should(Say(`#0\s+(starting|running)\s+\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z`)) Eventually(session).Should(Exit(0)) diff --git a/integration/v7/isolated/create_org_quota_command_test.go b/integration/v7/isolated/create_org_quota_command_test.go index d9c858d695f..45c05873888 100644 --- a/integration/v7/isolated/create_org_quota_command_test.go +++ b/integration/v7/isolated/create_org_quota_command_test.go @@ -1,6 +1,7 @@ package isolated import ( + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" . "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers" "code.cloudfoundry.org/cli/integration/helpers" . "github.com/onsi/ginkgo" @@ -32,7 +33,7 @@ var _ = Describe("create-org-quota command", func() { Eventually(session).Should(Say("NAME:")) Eventually(session).Should(Say("create-org-quota - Define a new quota for an organization")) Eventually(session).Should(Say("USAGE:")) - Eventually(session).Should(Say(`cf create-org-quota ORG_QUOTA \[-m TOTAL_MEMORY\] \[-i INSTANCE_MEMORY\] \[-r ROUTES\] \[-s SERVICE_INSTANCES\] \[-a APP_INSTANCES\] \[--allow-paid-service-plans\] \[--reserved-route-ports RESERVED_ROUTE_PORTS\]`)) + Eventually(session).Should(Say(`cf create-org-quota ORG_QUOTA \[-m TOTAL_MEMORY\] \[-i INSTANCE_MEMORY\] \[-r ROUTES\] \[-s SERVICE_INSTANCES\] \[-a APP_INSTANCES\] \[--allow-paid-service-plans\] \[--reserved-route-ports RESERVED_ROUTE_PORTS\] \[-l LOG_VOLUME\]`)) Eventually(session).Should(Say("ALIAS:")) Eventually(session).Should(Say("create-quota")) Eventually(session).Should(Say("OPTIONS:")) @@ -43,6 +44,7 @@ var _ = Describe("create-org-quota command", func() { Eventually(session).Should(Say(`-r\s+Total number of routes. -1 represents an unlimited amount. \(Default: 0\)`)) Eventually(session).Should(Say(`--reserved-route-ports\s+Maximum number of routes that may be created with ports. -1 represents an unlimited amount. \(Default: 0\)`)) Eventually(session).Should(Say(`-s\s+Total number of service instances. -1 represents an unlimited amount. \(Default: 0\)`)) + Eventually(session).Should(Say(`-l\s+Total log volume per second all processes can have, in bytes \(e.g. 128B, 4K, 1M\). -1 represents an unlimited amount. \(Default: -1\)`)) Eventually(session).Should(Say("SEE ALSO:")) Eventually(session).Should(Say("create-org, org-quotas, set-org-quota")) Eventually(session).Should(Exit(0)) @@ -119,7 +121,8 @@ var _ = Describe("create-org-quota command", func() { "-m", "4M", "-r", "6", "--reserved-route-ports", "5", - "-s", "7") + "-s", "7", + ) Eventually(session).Should(Say("Creating org quota %s as %s...", orgQuotaName, userName)) Eventually(session).Should(Say("OK")) Eventually(session).Should(Exit(0)) @@ -133,8 +136,30 @@ var _ = Describe("create-org-quota command", func() { Eventually(session).Should(Say(`paid service plans:\s+allowed`)) Eventually(session).Should(Say(`app instances:\s+2`)) Eventually(session).Should(Say(`route ports:\s+5`)) + Eventually(session).Should(Say(`log volume per second:\s+unlimited`)) Eventually(session).Should(Exit(0)) }) + + When("CAPI supports log rate limits", func() { + BeforeEach(func() { + helpers.SkipIfVersionLessThan(ccversion.MinVersionLogRateLimitingV3) + }) + + It("creates the quota with the specified values", func() { + + userName, _ := helpers.GetCredentials() + session := helpers.CF("create-org-quota", orgQuotaName, + "-l", "32K", + ) + Eventually(session).Should(Say("Creating org quota %s as %s...", orgQuotaName, userName)) + Eventually(session).Should(Say("OK")) + Eventually(session).Should(Exit(0)) + + session = helpers.CF("org-quota", orgQuotaName) + Eventually(session).Should(Say(`log volume per second:\s+32K`)) + Eventually(session).Should(Exit(0)) + }) + }) }) When("The flags are all set to -1", func() { @@ -146,7 +171,8 @@ var _ = Describe("create-org-quota command", func() { "-m", "-1", "-r", "-1", "-s", "-1", - "--reserved-route-ports", "-1") + "--reserved-route-ports", "-1", + ) Eventually(session).Should(Say("Creating org quota %s as %s...", orgQuotaName, userName)) Eventually(session).Should(Say("OK")) Eventually(session).Should(Exit(0)) @@ -158,8 +184,29 @@ var _ = Describe("create-org-quota command", func() { Eventually(session).Should(Say(`service instances:\s+unlimited`)) Eventually(session).Should(Say(`app instances:\s+unlimited`)) Eventually(session).Should(Say(`route ports:\s+unlimited`)) + Eventually(session).Should(Say(`log volume per second:\s+unlimited`)) Eventually(session).Should(Exit(0)) }) + + When("CAPI supports log rate limits", func() { + BeforeEach(func() { + helpers.SkipIfVersionLessThan(ccversion.MinVersionLogRateLimitingV3) + }) + + It("creates the quota with the specified values", func() { + userName, _ := helpers.GetCredentials() + session := helpers.CF("create-org-quota", orgQuotaName, + "-l", "-1", + ) + Eventually(session).Should(Say("Creating org quota %s as %s...", orgQuotaName, userName)) + Eventually(session).Should(Say("OK")) + Eventually(session).Should(Exit(0)) + + session = helpers.CF("org-quota", orgQuotaName) + Eventually(session).Should(Say(`log volume per second:\s+unlimited`)) + Eventually(session).Should(Exit(0)) + }) + }) }) }) diff --git a/integration/v7/isolated/create_space_quota_command_test.go b/integration/v7/isolated/create_space_quota_command_test.go index 969a2a540dd..ae73c5aa8e2 100644 --- a/integration/v7/isolated/create_space_quota_command_test.go +++ b/integration/v7/isolated/create_space_quota_command_test.go @@ -1,6 +1,7 @@ package isolated import ( + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" . "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers" "code.cloudfoundry.org/cli/integration/helpers" . "github.com/onsi/ginkgo" @@ -29,7 +30,7 @@ var _ = Describe("create-space-quota command", func() { Eventually(session).Should(Say("NAME:")) Eventually(session).Should(Say("create-space-quota - Define a new quota for a space")) Eventually(session).Should(Say("USAGE:")) - Eventually(session).Should(Say(`cf create-space-quota QUOTA \[-m TOTAL_MEMORY\] \[-i INSTANCE_MEMORY\] \[-r ROUTES\] \[-s SERVICE_INSTANCES\] \[-a APP_INSTANCES\] \[--allow-paid-service-plans\] \[--reserved-route-ports RESERVED_ROUTE_PORTS\]`)) + Eventually(session).Should(Say(`cf create-space-quota QUOTA \[-m TOTAL_MEMORY\] \[-i INSTANCE_MEMORY\] \[-r ROUTES\] \[-s SERVICE_INSTANCES\] \[-a APP_INSTANCES\] \[--allow-paid-service-plans\] \[--reserved-route-ports RESERVED_ROUTE_PORTS\] \[-l LOG_VOLUME\]`)) Eventually(session).Should(Say("OPTIONS:")) Eventually(session).Should(Say(`-a\s+Total number of application instances. \(Default: unlimited\)`)) Eventually(session).Should(Say(`--allow-paid-service-plans\s+Allow provisioning instances of paid service plans. \(Default: disallowed\)`)) @@ -38,6 +39,7 @@ var _ = Describe("create-space-quota command", func() { Eventually(session).Should(Say(`-r\s+Total number of routes. -1 represents an unlimited amount. \(Default: 0\)`)) Eventually(session).Should(Say(`--reserved-route-ports\s+Maximum number of routes that may be created with ports. -1 represents an unlimited amount. \(Default: 0\)`)) Eventually(session).Should(Say(`-s\s+Total number of service instances. -1 represents an unlimited amount. \(Default: 0\)`)) + Eventually(session).Should(Say(`-l\s+Total log volume per second all processes can have, in bytes \(e.g. 128B, 4K, 1M\). -1 represents an unlimited amount. \(Default: -1\).`)) Eventually(session).Should(Say("SEE ALSO:")) Eventually(session).Should(Say("create-space, set-space-quota, space-quotas")) Eventually(session).Should(Exit(0)) @@ -95,6 +97,7 @@ var _ = Describe("create-space-quota command", func() { Eventually(session).Should(Say(`paid service plans:\s+disallowed`)) Eventually(session).Should(Say(`app instances:\s+unlimited`)) Eventually(session).Should(Say(`route ports:\s+0`)) + Eventually(session).Should(Say(`log volume per second:\s+unlimited`)) Eventually(session).Should(Exit(0)) }) }) @@ -122,8 +125,26 @@ var _ = Describe("create-space-quota command", func() { Eventually(session).Should(Say(`paid service plans:\s+allowed`)) Eventually(session).Should(Say(`app instances:\s+2`)) Eventually(session).Should(Say(`route ports:\s+6`)) + Eventually(session).Should(Say(`log volume per second:\s+unlimited`)) Eventually(session).Should(Exit(0)) }) + + When("CAPI supports log rate limits", func() { + BeforeEach(func() { + helpers.SkipIfVersionLessThan(ccversion.MinVersionLogRateLimitingV3) + }) + + It("creates the quota with the specified values", func() { + session := helpers.CF("create-space-quota", spaceQuotaName, "-l", "2K") + Eventually(session).Should(Say("Creating space quota %s for org %s as %s...", spaceQuotaName, orgName, userName)) + Eventually(session).Should(Say("OK")) + Eventually(session).Should(Exit(0)) + + session = helpers.CF("space-quota", spaceQuotaName) + Eventually(session).Should(Say(`log volume per second:\s+2K`)) + Eventually(session).Should(Exit(0)) + }) + }) }) }) diff --git a/integration/v7/isolated/restart_command_test.go b/integration/v7/isolated/restart_command_test.go index 42bbd23c7a2..64bdf0cb274 100644 --- a/integration/v7/isolated/restart_command_test.go +++ b/integration/v7/isolated/restart_command_test.go @@ -12,6 +12,12 @@ import ( ) var _ = Describe("restart command", func() { + + const ( + instanceStatsTitles = `\s+state\s+since\s+cpu\s+memory\s+disk\s+logging\s+details` + instanceStatsValues = `#0\s+(starting|running)\s+\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z` + ) + var ( orgName string spaceName string @@ -105,8 +111,8 @@ var _ = Describe("restart command", func() { Eventually(session).Should(Say(`type:\s+web`)) Eventually(session).Should(Say(`instances:\s+1/1`)) Eventually(session).Should(Say(`memory usage:\s+\d+(M|G)`)) - Eventually(session).Should(Say(`\s+state\s+since\s+cpu\s+memory\s+disk\s+details`)) - Eventually(session).Should(Say(`#0\s+(starting|running)\s+\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z`)) + Eventually(session).Should(Say(instanceStatsTitles)) + Eventually(session).Should(Say(instanceStatsValues)) }) }) @@ -128,8 +134,8 @@ var _ = Describe("restart command", func() { Eventually(session).Should(Say(`type:\s+web`)) Eventually(session).Should(Say(`instances:\s+1/1`)) Eventually(session).Should(Say(`memory usage:\s+\d+(M|G)`)) - Eventually(session).Should(Say(`\s+state\s+since\s+cpu\s+memory\s+disk\s+details`)) - Eventually(session).Should(Say(`#0\s+(starting|running)\s+\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z`)) + Eventually(session).Should(Say(instanceStatsTitles)) + Eventually(session).Should(Say(instanceStatsValues)) Expect(session.Out.Contents()).NotTo(ContainSubstring("Staging app and tracing logs...")) @@ -165,8 +171,8 @@ var _ = Describe("restart command", func() { Eventually(session).Should(Say(`type:\s+web`)) Eventually(session).Should(Say(`instances:\s+1/1`)) Eventually(session).Should(Say(`memory usage:\s+\d+(M|G)`)) - Eventually(session).Should(Say(`\s+state\s+since\s+cpu\s+memory\s+disk\s+details`)) - Eventually(session).Should(Say(`#0\s+(starting|running)\s+\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z`)) + Eventually(session).Should(Say(instanceStatsTitles)) + Eventually(session).Should(Say(instanceStatsValues)) Eventually(session).Should(Exit(0)) Expect(session.Err).ToNot(Say(`timeout connecting to log server, no log will be shown`)) @@ -193,8 +199,8 @@ var _ = Describe("restart command", func() { Eventually(session).Should(Say(`type:\s+web`)) Eventually(session).Should(Say(`instances:\s+1/1`)) Eventually(session).Should(Say(`memory usage:\s+\d+(M|G)`)) - Eventually(session).Should(Say(`\s+state\s+since\s+cpu\s+memory\s+disk\s+details`)) - Eventually(session).Should(Say(`#0\s+(starting|running)\s+\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z`)) + Eventually(session).Should(Say(instanceStatsTitles)) + Eventually(session).Should(Say(instanceStatsValues)) Expect(session.Out.Contents()).NotTo(ContainSubstring("Staging app and tracing logs...")) Expect(session.Out.Contents()).NotTo(ContainSubstring("Stopping app...")) @@ -222,8 +228,8 @@ var _ = Describe("restart command", func() { Eventually(session).Should(Say(`type:\s+web`)) Eventually(session).Should(Say(`instances:\s+1/1`)) Eventually(session).Should(Say(`memory usage:\s+\d+(M|G)`)) - Eventually(session).Should(Say(`\s+state\s+since\s+cpu\s+memory\s+disk\s+details`)) - Eventually(session).Should(Say(`#0\s+(starting|running)\s+\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z`)) + Eventually(session).Should(Say(instanceStatsTitles)) + Eventually(session).Should(Say(instanceStatsValues)) Expect(session.Out.Contents()).NotTo(ContainSubstring("Stopping app...")) diff --git a/integration/v7/isolated/run_task_command_test.go b/integration/v7/isolated/run_task_command_test.go index 05ec1f3d159..3b3c7167f16 100644 --- a/integration/v7/isolated/run_task_command_test.go +++ b/integration/v7/isolated/run_task_command_test.go @@ -4,6 +4,7 @@ import ( "fmt" "path" + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" "code.cloudfoundry.org/cli/integration/helpers" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -19,7 +20,7 @@ var _ = Describe("run-task command", func() { Expect(session).To(Say("NAME:")) Expect(session).To(Say(" run-task - Run a one-off task on an app")) Expect(session).To(Say("USAGE:")) - Expect(session).To(Say(` cf run-task APP_NAME \[--command COMMAND\] \[-k DISK] \[-m MEMORY\] \[--name TASK_NAME\] \[--process PROCESS_TYPE\]`)) + Expect(session).To(Say(` cf run-task APP_NAME \[--command COMMAND\] \[-k DISK] \[-m MEMORY\] \[-l LOG_RATE_LIMIT\] \[--name TASK_NAME\] \[--process PROCESS_TYPE\]`)) Expect(session).To(Say("TIP:")) Expect(session).To(Say(" Use 'cf logs' to display the logs of the app and all its tasks. If your task name is unique, grep this command's output for the task name to view task-specific logs.")) Expect(session).To(Say("EXAMPLES:")) @@ -29,6 +30,7 @@ var _ = Describe("run-task command", func() { Expect(session).To(Say("OPTIONS:")) Expect(session).To(Say(` --command, -c\s+The command to execute`)) Expect(session).To(Say(` -k Disk limit \(e\.g\. 256M, 1024M, 1G\)`)) + Expect(session).To(Say(` -l Log rate limit per second, in bytes \(e\.g\. 128B, 4K, 1M\). -l=-1 represents unlimited`)) Expect(session).To(Say(` -m Memory limit \(e\.g\. 256M, 1024M, 1G\)`)) Expect(session).To(Say(` --name Name to give the task \(generated if omitted\)`)) Expect(session).To(Say(` --process Process type to use as a template for command, memory, and disk for the created task`)) @@ -130,6 +132,32 @@ var _ = Describe("run-task command", func() { }) }) + When("log rate limit is provided", func() { + BeforeEach(func() { + helpers.SkipIfVersionLessThan(ccversion.MinVersionLogRateLimitingV3) + }) + When("the provided log rate limit is invalid", func() { + It("displays error and exits 1", func() { + session := helpers.CF("run-task", appName, "--command", "echo hi", "-l", "invalid") + Eventually(session).Should(Exit(1)) + Expect(session.Err).Should(Say("Byte quantity must be an integer with a unit of measurement like B, K, KB, M, MB, G, or GB")) + + }) + }) + + When("the provided log rate limit is valid", func() { + It("runs the task with the provided log rate limit", func() { + logRateLimit := 1024 + session := helpers.CF("run-task", appName, "--command", "echo hi", "-l", fmt.Sprintf("%dB", logRateLimit)) + Eventually(session).Should(Exit(0)) + + session = helpers.CF("tasks", appName, "-v") + Eventually(session).Should(Exit(0)) + Expect(session).To(Say("\"log_rate_limit_in_bytes_per_second\": %d", logRateLimit)) + }) + }) + }) + When("task memory is provided", func() { When("the provided memory is invalid", func() { It("displays error and exits 1", func() { diff --git a/integration/v7/isolated/scale_command_test.go b/integration/v7/isolated/scale_command_test.go index 1c3d3c3e3fa..a256094ca43 100644 --- a/integration/v7/isolated/scale_command_test.go +++ b/integration/v7/isolated/scale_command_test.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" . "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers" "code.cloudfoundry.org/cli/integration/helpers" @@ -33,23 +34,24 @@ var _ = Describe("scale command", func() { It("appears in cf help -a", func() { session := helpers.CF("help", "-a") Eventually(session).Should(Exit(0)) - Expect(session).To(HaveCommandInCategoryWithDescription("scale", "APPS", "Change or view the instance count, disk space limit, and memory limit for an app")) + Expect(session).To(HaveCommandInCategoryWithDescription("scale", "APPS", "Change or view the instance count, disk space limit, memory limit, and log rate limit for an app")) }) It("displays command usage to output", func() { session := helpers.CF("scale", "--help") Eventually(session).Should(Say("NAME:")) - Eventually(session).Should(Say("scale - Change or view the instance count, disk space limit, and memory limit for an app")) + Eventually(session).Should(Say("scale - Change or view the instance count, disk space limit, memory limit, and log rate limit for an app")) Eventually(session).Should(Say("USAGE:")) - Eventually(session).Should(Say(`cf scale APP_NAME \[--process PROCESS\] \[-i INSTANCES\] \[-k DISK\] \[-m MEMORY\]`)) - Eventually(session).Should(Say("Modifying the app's disk or memory will cause the app to restart.")) + Eventually(session).Should(Say(`cf scale APP_NAME \[--process PROCESS\] \[-i INSTANCES\] \[-k DISK\] \[-m MEMORY\] \[-l LOG_RATE_LIMIT\]`)) + Eventually(session).Should(Say("Modifying the app's disk, memory, or log rate will cause the app to restart.")) Eventually(session).Should(Say("OPTIONS:")) Eventually(session).Should(Say(`-f\s+Force restart of app without prompt`)) Eventually(session).Should(Say(`-i\s+Number of instances`)) Eventually(session).Should(Say(`-k\s+Disk limit \(e\.g\. 256M, 1024M, 1G\)`)) + Eventually(session).Should(Say(`-l\s+Log rate limit per second, in bytes \(e\.g\. 128B, 4K, 1M\). -l=-1 represents unlimited`)) Eventually(session).Should(Say(`-m\s+Memory limit \(e\.g\. 256M, 1024M, 1G\)`)) Eventually(session).Should(Say(`--process\s+App process to scale \(Default: web\)`)) @@ -229,6 +231,37 @@ var _ = Describe("scale command", func() { }) }) + When("Scaling the log rate limit", func() { + BeforeEach(func() { + helpers.SkipIfVersionLessThan(ccversion.MinVersionLogRateLimitingV3) + }) + + It("scales log rate limit to 1M", func() { + buffer := NewBuffer() + _, err := buffer.Write([]byte("y\n")) + Expect(err).ToNot(HaveOccurred()) + session := helpers.CFWithStdin(buffer, "scale", appName, "-l", "1M") + Eventually(session).Should(Exit(0)) + Expect(session).To(Say(`Scaling app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) + Expect(session).To(Say(`This will cause the app to restart\. Are you sure you want to scale %s\? \[yN\]:`, appName)) + Expect(session).To(Say(`Stopping app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) + Expect(session).To(Say(`Starting app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) + Expect(session).To(Say(`Instances starting\.\.\.`)) + + helpers.WaitForLogRateLimitToTakeEffect(appName, 0, 0, false, "1M") + }) + + When("-f flag provided", func() { + It("scales without prompt", func() { + session := helpers.CF("scale", appName, "-l", "1M", "-f") + Eventually(session).Should(Exit(0)) + Expect(session).To(Say("Scaling app %s in org %s / space %s as %s...", appName, orgName, spaceName, userName)) + + helpers.WaitForLogRateLimitToTakeEffect(appName, 0, 0, false, "1M") + }) + }) + }) + When("Scaling to 0 instances", func() { It("scales to 0 instances", func() { session := helpers.CF("scale", appName, "-i", "0") diff --git a/integration/v7/isolated/space_quota_command_test.go b/integration/v7/isolated/space_quota_command_test.go index 34798df7ef7..d30a0fa7aee 100644 --- a/integration/v7/isolated/space_quota_command_test.go +++ b/integration/v7/isolated/space_quota_command_test.go @@ -85,6 +85,7 @@ var _ = Describe("space-quota command", func() { Eventually(session).Should(Say(`paid service plans:\s+allowed`)) Eventually(session).Should(Say(`app instances:\s+unlimited`)) Eventually(session).Should(Say(`route ports:\s+0`)) + Eventually(session).Should(Say(`log volume per second:\s+unlimited`)) Eventually(session).Should(Exit(0)) }) diff --git a/integration/v7/isolated/space_quotas_command_test.go b/integration/v7/isolated/space_quotas_command_test.go index 880a561560b..c70a7392f60 100644 --- a/integration/v7/isolated/space_quotas_command_test.go +++ b/integration/v7/isolated/space_quotas_command_test.go @@ -62,8 +62,8 @@ var _ = Describe("space-quotas command", func() { It("lists the space quotas", func() { session := helpers.CF("space-quotas") Eventually(session).Should(Say(`Getting space quotas for org %s as %s\.\.\.`, orgName, userName)) - Eventually(session).Should(Say(`name\s+total memory\s+instance memory\s+routes\s+service instances\s+paid service plans\s+app instances\s+route ports`)) - Eventually(session).Should(Say(`%s\s+%s\s+%s\s+%s\s+%s\s+%s\s+%s\s+%s`, quotaName, totalMemory, instanceMemory, routes, serviceInstances, "allowed", "unlimited", reservedRoutePorts)) + Eventually(session).Should(Say(`name\s+total memory\s+instance memory\s+routes\s+service instances\s+paid service plans\s+app instances\s+route ports\s+log volume per second`)) + Eventually(session).Should(Say(`%s\s+%s\s+%s\s+%s\s+%s\s+%s\s+%s\s+%s\s+%s`, quotaName, totalMemory, instanceMemory, routes, serviceInstances, "allowed", "unlimited", reservedRoutePorts, "unlimited")) Eventually(session).Should(Exit(0)) }) diff --git a/integration/v7/isolated/start_command_test.go b/integration/v7/isolated/start_command_test.go index 00d7887f79f..b1bbfac5a81 100644 --- a/integration/v7/isolated/start_command_test.go +++ b/integration/v7/isolated/start_command_test.go @@ -130,7 +130,7 @@ var _ = Describe("start command", func() { Eventually(session).Should(Say(`type:\s+web`)) Eventually(session).Should(Say(`instances:\s+1/1`)) Eventually(session).Should(Say(`memory usage:\s+32M`)) - Eventually(session).Should(Say(`\s+state\s+since\s+cpu\s+memory\s+disk\s+details`)) + Eventually(session).Should(Say(`\s+state\s+since\s+cpu\s+memory\s+disk\s+logging\s+details`)) Eventually(session).Should(Say(`#0\s+(starting|running)\s+\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z`)) Eventually(session).Should(Exit(0)) @@ -187,7 +187,7 @@ var _ = Describe("start command", func() { Eventually(session).Should(Say(`requested state:\s+started`)) Eventually(session).Should(Say(`type:\s+web`)) Eventually(session).Should(Say(`instances:\s+1/1`)) - Eventually(session).Should(Say(`\s+state\s+since\s+cpu\s+memory\s+disk\s+details`)) + Eventually(session).Should(Say(`\s+state\s+since\s+cpu\s+memory\s+disk\s+logging\s+details`)) Eventually(session).Should(Say(`#0\s+(starting|running)\s+\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z`)) Eventually(session).Should(Exit(0)) diff --git a/integration/v7/isolated/update_org_quota_command_test.go b/integration/v7/isolated/update_org_quota_command_test.go index e38efddd291..381c4004f44 100644 --- a/integration/v7/isolated/update_org_quota_command_test.go +++ b/integration/v7/isolated/update_org_quota_command_test.go @@ -1,6 +1,7 @@ package isolated import ( + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" "code.cloudfoundry.org/cli/integration/helpers" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -16,7 +17,7 @@ var _ = Describe("update-org-quota command", func() { Eventually(session).Should(Say("NAME:")) Eventually(session).Should(Say("update-org-quota - Update an existing organization quota")) Eventually(session).Should(Say("USAGE:")) - Eventually(session).Should(Say(`cf update-org-quota QUOTA [-m TOTAL_MEMORY] [-i INSTANCE_MEMORY] \[-n NEW_NAME\] \[-r ROUTES\] \[-s SERVICE_INSTANCES\] \[-a APP_INSTANCES\] \[--allow-paid-service-plans | --disallow-paid-service-plans\] \[--reserved-route-ports RESERVED_ROUTE_PORTS\]`)) + Eventually(session).Should(Say(`cf update-org-quota QUOTA [-m TOTAL_MEMORY] [-i INSTANCE_MEMORY] \[-n NEW_NAME\] \[-r ROUTES\] \[-s SERVICE_INSTANCES\] \[-a APP_INSTANCES\] \[--allow-paid-service-plans | --disallow-paid-service-plans\] \[--reserved-route-ports RESERVED_ROUTE_PORTS\] \[-l LOG_VOLUME\]`)) Eventually(session).Should(Say("ALIAS:")) Eventually(session).Should(Say("update-quota")) Eventually(session).Should(Say("OPTIONS:")) @@ -29,6 +30,7 @@ var _ = Describe("update-org-quota command", func() { Eventually(session).Should(Say(`-r\s+Total number of routes. -1 represents an unlimited amount.`)) Eventually(session).Should(Say(`--reserved-route-ports\s+Maximum number of routes that may be created with ports. -1 represents an unlimited amount.`)) Eventually(session).Should(Say(`-s\s+Total number of service instances. -1 represents an unlimited amount.`)) + Eventually(session).Should(Say(`-l\s+Total log volume per second all processes can have, in bytes \(e.g. 128B, 4K, 1M\). -1 represents an unlimited amount.`)) Eventually(session).Should(Say("SEE ALSO:")) Eventually(session).Should(Say("org, org-quota")) Eventually(session).Should(Exit(0)) @@ -83,9 +85,27 @@ var _ = Describe("update-org-quota command", func() { Eventually(session).Should(Say(`paid service plans:\s+%s`, "disallowed")) Eventually(session).Should(Say(`app instances:\s+%s`, appInstances)) Eventually(session).Should(Say(`route ports:\s+%s`, reservedRoutePorts)) + Eventually(session).Should(Say(`log volume per second:\s+unlimited`)) Eventually(session).Should(Exit(0)) }) + When("CAPI supports log rate limits", func() { + BeforeEach(func() { + helpers.SkipIfVersionLessThan(ccversion.MinVersionLogRateLimitingV3) + }) + + It("updates a quota", func() { + logVolume := "500B" + session := helpers.CF("update-org-quota", quotaName, "-l", logVolume) + Eventually(session).Should(Say(`Updating org quota %s as %s\.\.\.`, quotaName, username)) + Eventually(session).Should(Exit(0)) + + session = helpers.CF("org-quota", quotaName) + Eventually(session).Should(Say(`log volume per second:\s+%s`, logVolume)) + Eventually(session).Should(Exit(0)) + }) + }) + When("the -n rename flag is provided", func() { var newQuotaName string diff --git a/integration/v7/isolated/update_space_quota_command_test.go b/integration/v7/isolated/update_space_quota_command_test.go index 5d70363ba18..4b2637d9610 100644 --- a/integration/v7/isolated/update_space_quota_command_test.go +++ b/integration/v7/isolated/update_space_quota_command_test.go @@ -1,6 +1,7 @@ package isolated import ( + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" "code.cloudfoundry.org/cli/integration/helpers" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -24,7 +25,7 @@ var _ = Describe("update-space-quota command", func() { Eventually(session).Should(Say("NAME:")) Eventually(session).Should(Say("update-space-quota - Update an existing space quota")) Eventually(session).Should(Say("USAGE:")) - Eventually(session).Should(Say(`cf update-space-quota QUOTA \[-m TOTAL_MEMORY\] \[-i INSTANCE_MEMORY\] \[-n NEW_NAME\] \[-r ROUTES\] \[-s SERVICE_INSTANCES\] \[-a APP_INSTANCES\] \[--allow-paid-service-plans | --disallow-paid-service-plans\] \[--allow-paid-service-plans\] \[--reserved-route-ports RESERVED_ROUTE_PORTS\]`)) + Eventually(session).Should(Say(`cf update-space-quota QUOTA \[-m TOTAL_MEMORY\] \[-i INSTANCE_MEMORY\] \[-n NEW_NAME\] \[-r ROUTES\] \[-s SERVICE_INSTANCES\] \[-a APP_INSTANCES\] \[--allow-paid-service-plans | --disallow-paid-service-plans\] \[--allow-paid-service-plans\] \[--reserved-route-ports RESERVED_ROUTE_PORTS\] \[-l LOG_VOLUME\]`)) Eventually(session).Should(Say("OPTIONS:")) Eventually(session).Should(Say(`-a\s+Total number of application instances. -1 represents an unlimited amount.`)) Eventually(session).Should(Say(`--allow-paid-service-plans\s+Allow provisioning instances of paid service plans.`)) @@ -35,6 +36,7 @@ var _ = Describe("update-space-quota command", func() { Eventually(session).Should(Say(`-r\s+Total number of routes. -1 represents an unlimited amount.`)) Eventually(session).Should(Say(`--reserved-route-ports\s+Maximum number of routes that may be created with ports. -1 represents an unlimited amount.`)) Eventually(session).Should(Say(`-s\s+Total number of service instances. -1 represents an unlimited amount.`)) + Eventually(session).Should(Say(`-l\s+Total log volume per second all processes can have, in bytes \(e.g. 128B, 4K, 1M\). -1 represents an unlimited amount.`)) Eventually(session).Should(Say("SEE ALSO:")) Eventually(session).Should(Say("space, space-quota, space-quotas")) Eventually(session).Should(Exit(0)) @@ -94,9 +96,28 @@ var _ = Describe("update-space-quota command", func() { Eventually(session).Should(Say(`paid service plans:\s+%s`, "allowed")) Eventually(session).Should(Say(`app instances:\s+%s`, appInstances)) Eventually(session).Should(Say(`route ports:\s+%s`, reservedRoutePorts)) + Eventually(session).Should(Say(`log volume per second:\s+%s`, "unlimited")) Eventually(session).Should(Exit(0)) }) + When("CAPI supports log rate limits", func() { + BeforeEach(func() { + helpers.SkipIfVersionLessThan(ccversion.MinVersionLogRateLimitingV3) + }) + + It("updates a quota", func() { + logVolume := "500B" + session := helpers.CF("update-space-quota", quotaName, "-l", logVolume) + Eventually(session).Should(Say("Updating space quota %s for org %s as %s...", quotaName, orgName, userName)) + Eventually(session).Should(Say("OK")) + Eventually(session).Should(Exit(0)) + + session = helpers.CF("space-quota", quotaName) + Eventually(session).Should(Say(`log volume per second:\s+%s`, logVolume)) + Eventually(session).Should(Exit(0)) + }) + }) + When("the named quota does not exist", func() { It("displays a missing quota error message and fails", func() { session := helpers.CF("update-space-quota", "bogota") diff --git a/integration/v7/push/combination_manifest_and_flag_test.go b/integration/v7/push/combination_manifest_and_flag_test.go index 315767dd266..f870b9fff7b 100644 --- a/integration/v7/push/combination_manifest_and_flag_test.go +++ b/integration/v7/push/combination_manifest_and_flag_test.go @@ -209,6 +209,7 @@ var _ = Describe("push with a simple manifest and flags", func() { Entry("health check type", "-u", "port"), Entry("instances", "-i", "10"), Entry("memory", "-m", "100M"), + Entry("log rate limit", "-l", "5K"), Entry("no route", "--no-route"), Entry("stack", "-s", "something"), ) diff --git a/integration/v7/push/help_test.go b/integration/v7/push/help_test.go index 526c611d0fc..1529492af15 100644 --- a/integration/v7/push/help_test.go +++ b/integration/v7/push/help_test.go @@ -31,6 +31,7 @@ var _ = Describe("help", func() { "[-i NUM_INSTANCES]", "[-k DISK]", "[-m MEMORY]", + "[-l LOG_RATE_LIMIT]", "[-p PATH]", "[-s STACK]", "[-t HEALTH_TIMEOUT]", @@ -55,6 +56,7 @@ var _ = Describe("help", func() { "[-i NUM_INSTANCES]", "[-k DISK]", "[-m MEMORY]", + "[-l LOG_RATE_LIMIT]", "[-p PATH]", "[-s STACK]", "[-t HEALTH_TIMEOUT]", @@ -68,15 +70,16 @@ var _ = Describe("help", func() { assertUsage(session, buildpackAppUsage, dockerAppUsage) Eventually(session).Should(Say("OPTIONS:")) - Eventually(session).Should(Say(`app-start-timeout, -t`)) + Eventually(session).Should(Say(`--app-start-timeout, -t`)) Eventually(session).Should(Say(`--buildpack, -b`)) - Eventually(session).Should(Say(`disk, -k`)) + Eventually(session).Should(Say(`--disk, -k`)) Eventually(session).Should(Say(`--docker-image, -o`)) Eventually(session).Should(Say(`--docker-username`)) Eventually(session).Should(Say(`--droplet`)) Eventually(session).Should(Say(`--endpoint`)) Eventually(session).Should(Say(`--health-check-type, -u`)) Eventually(session).Should(Say(`--instances, -i`)) + Eventually(session).Should(Say(`--log-rate-limit, -l\s+Log rate limit per second, in bytes \(e.g. 128B, 4K, 1M\). -l=-1 represents unlimited`)) Eventually(session).Should(Say(`--manifest, -f`)) Eventually(session).Should(Say(`--memory, -m`)) Eventually(session).Should(Say(`--no-manifest`)) diff --git a/integration/v7/push/log_rate_limit_flag_test.go b/integration/v7/push/log_rate_limit_flag_test.go new file mode 100644 index 00000000000..a8797b43db7 --- /dev/null +++ b/integration/v7/push/log_rate_limit_flag_test.go @@ -0,0 +1,35 @@ +package push + +import ( + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" + "code.cloudfoundry.org/cli/integration/helpers" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gexec" +) + +var _ = Describe("push with log rate limit flag", func() { + var ( + appName string + ) + + BeforeEach(func() { + helpers.SkipIfVersionLessThan(ccversion.MinVersionLogRateLimitingV3) + + appName = helpers.NewAppName() + }) + + Context("when the -l flag is provided with application log rate limit", func() { + It("creates the app with the specified log rate limit", func() { + helpers.WithHelloWorldApp(func(dir string) { + session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, + PushCommandName, appName, + "-l", "5K", + ) + Eventually(session).Should(Exit(0)) + }) + + helpers.WaitForLogRateLimitToTakeEffect(appName, 0, 0, false, "5K") + }) + }) +}) diff --git a/resources/process_resource.go b/resources/process_resource.go index 5376f8e6ab6..afbf20a09a0 100644 --- a/resources/process_resource.go +++ b/resources/process_resource.go @@ -21,6 +21,7 @@ type Process struct { Instances types.NullInt MemoryInMB types.NullUint64 DiskInMB types.NullUint64 + LogRateLimitInBPS types.NullInt AppGUID string } @@ -31,6 +32,7 @@ func (p Process) MarshalJSON() ([]byte, error) { marshalInstances(p, &ccProcess) marshalMemory(p, &ccProcess) marshalDisk(p, &ccProcess) + marshalLogRateLimit(p, &ccProcess) marshalHealthCheck(p, &ccProcess) return json.Marshal(ccProcess) @@ -38,13 +40,14 @@ func (p Process) MarshalJSON() ([]byte, error) { func (p *Process) UnmarshalJSON(data []byte) error { var ccProcess struct { - Command types.FilteredString `json:"command"` - DiskInMB types.NullUint64 `json:"disk_in_mb"` - GUID string `json:"guid"` - Instances types.NullInt `json:"instances"` - MemoryInMB types.NullUint64 `json:"memory_in_mb"` - Type string `json:"type"` - Relationships Relationships `json:"relationships"` + Command types.FilteredString `json:"command"` + DiskInMB types.NullUint64 `json:"disk_in_mb"` + GUID string `json:"guid"` + Instances types.NullInt `json:"instances"` + MemoryInMB types.NullUint64 `json:"memory_in_mb"` + LogRateLimitInBPS types.NullInt `json:"log_rate_limit_in_bytes_per_second"` + Type string `json:"type"` + Relationships Relationships `json:"relationships"` HealthCheck struct { Type constant.HealthCheckType `json:"type"` @@ -70,6 +73,7 @@ func (p *Process) UnmarshalJSON(data []byte) error { p.HealthCheckType = ccProcess.HealthCheck.Type p.Instances = ccProcess.Instances p.MemoryInMB = ccProcess.MemoryInMB + p.LogRateLimitInBPS = ccProcess.LogRateLimitInBPS p.Type = ccProcess.Type p.AppGUID = ccProcess.Relationships[constant.RelationshipTypeApplication].GUID @@ -86,10 +90,11 @@ type healthCheck struct { } type marshalProcess struct { - Command interface{} `json:"command,omitempty"` - Instances json.Number `json:"instances,omitempty"` - MemoryInMB json.Number `json:"memory_in_mb,omitempty"` - DiskInMB json.Number `json:"disk_in_mb,omitempty"` + Command interface{} `json:"command,omitempty"` + Instances json.Number `json:"instances,omitempty"` + MemoryInMB json.Number `json:"memory_in_mb,omitempty"` + DiskInMB json.Number `json:"disk_in_mb,omitempty"` + LogRateLimitInBPS json.Number `json:"log_rate_limit_in_bytes_per_second,omitempty"` HealthCheck *healthCheck `json:"health_check,omitempty"` } @@ -129,3 +134,9 @@ func marshalMemory(p Process, ccProcess *marshalProcess) { ccProcess.MemoryInMB = json.Number(fmt.Sprint(p.MemoryInMB.Value)) } } + +func marshalLogRateLimit(p Process, ccProcess *marshalProcess) { + if p.LogRateLimitInBPS.IsSet { + ccProcess.LogRateLimitInBPS = json.Number(fmt.Sprint(p.LogRateLimitInBPS.Value)) + } +} diff --git a/resources/process_resource_test.go b/resources/process_resource_test.go index 394e8f1a61e..946c6ab9c70 100644 --- a/resources/process_resource_test.go +++ b/resources/process_resource_test.go @@ -64,6 +64,17 @@ var _ = Describe("Process", func() { }) }) + When("log rate limit is provided", func() { + BeforeEach(func() { + process = resources.Process{ + LogRateLimitInBPS: types.NullInt{Value: 1024, IsSet: true}, + } + }) + + It("sets the log rate limit to be set", func() { + Expect(string(processBytes)).To(MatchJSON(`{"log_rate_limit_in_bytes_per_second": 1024}`)) + }) + }) When("health check type http is provided", func() { BeforeEach(func() { process = resources.Process{ @@ -126,6 +137,17 @@ var _ = Describe("Process", func() { err = json.Unmarshal(processBytes, &process) Expect(err).ToNot(HaveOccurred()) }) + When("log rate limit is provided", func() { + BeforeEach(func() { + processBytes = []byte(`{"log_rate_limit_in_bytes_per_second": 512}`) + }) + + It("sets the log rate limit", func() { + Expect(process).To(MatchFields(IgnoreExtras, Fields{ + "LogRateLimitInBPS": Equal(types.NullInt{Value: 512, IsSet: true}), + })) + }) + }) When("health check type http is provided", func() { BeforeEach(func() { processBytes = []byte(`{"health_check":{"type":"http", "data": {"endpoint": "some-endpoint"}}}`) diff --git a/resources/quota_resource.go b/resources/quota_resource.go index f78ec80699b..8a896c14582 100644 --- a/resources/quota_resource.go +++ b/resources/quota_resource.go @@ -23,6 +23,7 @@ type AppLimit struct { TotalMemory *types.NullInt `json:"total_memory_in_mb,omitempty"` InstanceMemory *types.NullInt `json:"per_process_memory_in_mb,omitempty"` TotalAppInstances *types.NullInt `json:"total_instances,omitempty"` + TotalLogVolume *types.NullInt `json:"log_rate_limit_in_bytes_per_second,omitempty"` } func (al *AppLimit) UnmarshalJSON(rawJSON []byte) error { @@ -57,6 +58,13 @@ func (al *AppLimit) UnmarshalJSON(rawJSON []byte) error { } } + if al.TotalLogVolume == nil { + al.TotalLogVolume = &types.NullInt{ + IsSet: false, + Value: 0, + } + } + return nil } diff --git a/resources/quota_resource_test.go b/resources/quota_resource_test.go index fb5e96ed80b..14273d96ee1 100644 --- a/resources/quota_resource_test.go +++ b/resources/quota_resource_test.go @@ -20,6 +20,9 @@ var _ = Describe("quota limits", func() { Entry("total memory", AppLimit{TotalMemory: &types.NullInt{IsSet: true, Value: 1}}, []byte(`{"total_memory_in_mb":1}`)), Entry("total memory", AppLimit{TotalMemory: nil}, []byte(`{}`)), Entry("total memory", AppLimit{TotalMemory: &types.NullInt{IsSet: false}}, []byte(`{"total_memory_in_mb":null}`)), + Entry("total log volume", AppLimit{TotalLogVolume: &types.NullInt{IsSet: true, Value: 1}}, []byte(`{"log_rate_limit_in_bytes_per_second":1}`)), + Entry("total log volume", AppLimit{TotalLogVolume: nil}, []byte(`{}`)), + Entry("total log volume", AppLimit{TotalLogVolume: &types.NullInt{IsSet: false}}, []byte(`{"log_rate_limit_in_bytes_per_second":null}`)), Entry("instance memory", AppLimit{InstanceMemory: &types.NullInt{IsSet: true, Value: 1}}, []byte(`{"per_process_memory_in_mb":1}`)), Entry("instance memory", AppLimit{InstanceMemory: nil}, []byte(`{}`)), Entry("instance memory", AppLimit{InstanceMemory: &types.NullInt{IsSet: false}}, []byte(`{"per_process_memory_in_mb":null}`)), @@ -37,35 +40,48 @@ var _ = Describe("quota limits", func() { }, Entry( "no null values", - []byte(`{"total_memory_in_mb":1,"per_process_memory_in_mb":2,"total_instances":3}`), + []byte(`{"total_memory_in_mb":1,"per_process_memory_in_mb":2,"total_instances":3,"log_rate_limit_in_bytes_per_second":4}`), AppLimit{ TotalMemory: &types.NullInt{IsSet: true, Value: 1}, InstanceMemory: &types.NullInt{IsSet: true, Value: 2}, TotalAppInstances: &types.NullInt{IsSet: true, Value: 3}, + TotalLogVolume: &types.NullInt{IsSet: true, Value: 4}, }), Entry( "total memory is null", - []byte(`{"total_memory_in_mb":null,"per_process_memory_in_mb":2,"total_instances":3}`), + []byte(`{"total_memory_in_mb":null,"per_process_memory_in_mb":2,"total_instances":3,"log_rate_limit_in_bytes_per_second":4}`), AppLimit{ TotalMemory: &types.NullInt{IsSet: false, Value: 0}, InstanceMemory: &types.NullInt{IsSet: true, Value: 2}, TotalAppInstances: &types.NullInt{IsSet: true, Value: 3}, + TotalLogVolume: &types.NullInt{IsSet: true, Value: 4}, }), Entry( "per process memory is null", - []byte(`{"total_memory_in_mb":1,"per_process_memory_in_mb":null,"total_instances":3}`), + []byte(`{"total_memory_in_mb":1,"per_process_memory_in_mb":null,"total_instances":3,"log_rate_limit_in_bytes_per_second":4}`), AppLimit{ TotalMemory: &types.NullInt{IsSet: true, Value: 1}, InstanceMemory: &types.NullInt{IsSet: false, Value: 0}, TotalAppInstances: &types.NullInt{IsSet: true, Value: 3}, + TotalLogVolume: &types.NullInt{IsSet: true, Value: 4}, }), Entry( "total instances is null", - []byte(`{"total_memory_in_mb":1,"per_process_memory_in_mb":2,"total_instances":null}`), + []byte(`{"total_memory_in_mb":1,"per_process_memory_in_mb":2,"total_instances":null,"log_rate_limit_in_bytes_per_second":4}`), AppLimit{ TotalMemory: &types.NullInt{IsSet: true, Value: 1}, InstanceMemory: &types.NullInt{IsSet: true, Value: 2}, TotalAppInstances: &types.NullInt{IsSet: false, Value: 0}, + TotalLogVolume: &types.NullInt{IsSet: true, Value: 4}, + }), + Entry( + "total log volume is null", + []byte(`{"total_memory_in_mb":1,"per_process_memory_in_mb":2,"total_instances":3,"log_rate_limit_in_bytes_per_second":null}`), + AppLimit{ + TotalMemory: &types.NullInt{IsSet: true, Value: 1}, + InstanceMemory: &types.NullInt{IsSet: true, Value: 2}, + TotalAppInstances: &types.NullInt{IsSet: true, Value: 3}, + TotalLogVolume: &types.NullInt{IsSet: false, Value: 0}, }), ) }) diff --git a/resources/space_quota_resource.go b/resources/space_quota_resource.go index 0fc2a110227..f1e6742eef5 100644 --- a/resources/space_quota_resource.go +++ b/resources/space_quota_resource.go @@ -23,6 +23,9 @@ func (sq SpaceQuota) MarshalJSON() ([]byte, error) { if sq.Apps.TotalAppInstances != nil { appLimits["total_instances"] = sq.Apps.TotalAppInstances } + if sq.Apps.TotalLogVolume != nil { + appLimits["log_rate_limit_in_bytes_per_second"] = sq.Apps.TotalLogVolume + } serviceLimits := map[string]interface{}{} if sq.Services.PaidServicePlans != nil { diff --git a/resources/task_resource.go b/resources/task_resource.go index 4bc1f96f012..62f1f500ed4 100644 --- a/resources/task_resource.go +++ b/resources/task_resource.go @@ -15,6 +15,8 @@ type Task struct { DiskInMB uint64 `json:"disk_in_mb,omitempty"` // GUID represents the unique task identifier. GUID string `json:"guid,omitempty"` + // LogRateLimitInBPS represents the log rate limit in bytes allocated for the task. + LogRateLimitInBPS int `json:"log_rate_limit_in_bytes_per_second,omitempty"` // MemoryInMB represents the memory in MB allocated for the task. MemoryInMB uint64 `json:"memory_in_mb,omitempty"` // Name represents the name of the task. diff --git a/util/manifestparser/application.go b/util/manifestparser/application.go index c51121f8e61..4eae68b1ecc 100644 --- a/util/manifestparser/application.go +++ b/util/manifestparser/application.go @@ -30,6 +30,7 @@ type Application struct { RandomRoute bool `yaml:"random-route,omitempty"` DefaultRoute bool `yaml:"default-route,omitempty"` Stack string `yaml:"stack,omitempty"` + LogRateLimit string `yaml:"log-rate-limit-per-second,omitempty"` RemainingManifestFields map[string]interface{} `yaml:"-,inline"` } diff --git a/util/manifestparser/application_test.go b/util/manifestparser/application_test.go index 467274711a9..d39eb28db8a 100644 --- a/util/manifestparser/application_test.go +++ b/util/manifestparser/application_test.go @@ -349,6 +349,22 @@ processes: }) }) + Context("when a log rate limit is provided", func() { + BeforeEach(func() { + rawYAML = []byte(`--- +processes: +- log-rate-limit-per-second: 512M +`) + }) + + It("unmarshals the processes property with the log rate limit", func() { + Expect(executeErr).ToNot(HaveOccurred()) + Expect(application.Processes).To(Equal([]Process{ + {LogRateLimit: "512M", RemainingManifestFields: emptyMap}, + })) + }) + }) + Context("when an unknown field is provided", func() { BeforeEach(func() { rawYAML = []byte(`--- @@ -392,6 +408,19 @@ processes: Expect(remarshalledYaml).To(MatchYAML(rawYAML)) }) }) + + Context("when a log rate limit is provided", func() { + BeforeEach(func() { + rawYAML = []byte(`--- +log-rate-limit-per-second: 5K +`) + }) + + It("unmarshals the log rate limit", func() { + Expect(executeErr).ToNot(HaveOccurred()) + Expect(application.LogRateLimit).To(Equal("5K")) + }) + }) }) Describe("SetStartCommand", func() { diff --git a/util/manifestparser/process.go b/util/manifestparser/process.go index 611cbf2a1df..6481225a6af 100644 --- a/util/manifestparser/process.go +++ b/util/manifestparser/process.go @@ -16,6 +16,7 @@ type Process struct { Instances *int `yaml:"instances,omitempty"` Memory string `yaml:"memory,omitempty"` Type string `yaml:"type"` + LogRateLimit string `yaml:"log-rate-limit-per-second,omitempty"` RemainingManifestFields map[string]interface{} `yaml:"-,inline"` } diff --git a/util/manifestparser/process_test.go b/util/manifestparser/process_test.go index 33753ba85bf..564c2dbea3e 100644 --- a/util/manifestparser/process_test.go +++ b/util/manifestparser/process_test.go @@ -77,6 +77,5 @@ var _ = Describe("Process", func() { Expect(process).To(Equal(Process{DiskQuota: "5G", RemainingManifestFields: map[string]interface{}{}})) }) }) - }) }) From b94f8f204af433f213ba383d95f44e1e606d8f49 Mon Sep 17 00:00:00 2001 From: "M. Oleske" Date: Tue, 20 Sep 2022 17:13:42 -0400 Subject: [PATCH 045/248] =?UTF-8?q?Use=20jq=20instead=20of=20grep=20-P=20f?= =?UTF-8?q?or=20finding=20users=20to=20delete=20during=20integrat=E2=80=A6?= =?UTF-8?q?=20(#2319)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use jq instead of grep -P for finding users to delete during integration cleanup * remove per page cause we're already iterating over a known set of pages --- bin/cleanup-integration | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bin/cleanup-integration b/bin/cleanup-integration index 3dd18f8c022..ba0c275bc52 100755 --- a/bin/cleanup-integration +++ b/bin/cleanup-integration @@ -62,11 +62,10 @@ for stack in $(cf stacks | awk '/INTEGRATION-STACK/ { print $1 }'); do cf curl -X DELETE "/v3/stacks/$(cf stack --guid $stack)" done -CF_USERS=$(cf curl /v3/users | grep -oP '(?<="total_results":)[^"]*' |grep -o '[0-9]\+') -USER_PAGES=$(( $CF_USERS / 50 + 1)) +USER_PAGES=$(cf curl /v3/users | jq -r .pagination.total_pages) for ((i=1; i<=${USER_PAGES}; i++)) ; do - cf curl "/v3/users?per_page=50&page=${i}" | \ + cf curl "/v3/users?&page=${i}" | \ jq -r .resources[].username | \ grep -i -e ^integration-user -e CATS- | \ xargs_func cf delete-user -f || echo From b2e07e2bc37c0188ea755c069c33ff9016173bf3 Mon Sep 17 00:00:00 2001 From: "M. Oleske" Date: Tue, 20 Sep 2022 17:25:07 -0400 Subject: [PATCH 046/248] Allow user to rename app if buildpack is deleted (#2321) * Add new UpdateApplicationName functions for actor and client. Change RenameApplicationByNameAndSpaceGuid to use new UpdateApplicationName function. * Add UpdateApplicationName to cloud-controller-client interface. * create ApplicationNameOnly struct that marshalls correctly Co-authored-by: Ryker Reed --- actor/v7action/application.go | 15 ++- actor/v7action/application_test.go | 84 ++++++++++++++-- actor/v7action/cloud_controller_client.go | 1 + .../fake_cloud_controller_client.go | 85 ++++++++++++++++ api/cloudcontroller/ccv3/application.go | 13 +++ api/cloudcontroller/ccv3/application_test.go | 98 +++++++++++++++++++ resources/application_resource.go | 6 ++ 7 files changed, 291 insertions(+), 11 deletions(-) diff --git a/actor/v7action/application.go b/actor/v7action/application.go index 95f1abb4694..a7a8d6ea7c5 100644 --- a/actor/v7action/application.go +++ b/actor/v7action/application.go @@ -400,6 +400,17 @@ func (actor Actor) UpdateApplication(app resources.Application) (resources.Appli return updatedApp, Warnings(warnings), nil } +// UpdateApplicationName updates the name of an application +func (actor Actor) UpdateApplicationName(newAppName string, appGUID string) (resources.Application, Warnings, error) { + + updatedApp, warnings, err := actor.CloudControllerClient.UpdateApplicationName(newAppName, appGUID) + if err != nil { + return resources.Application{}, Warnings(warnings), err + } + + return updatedApp, Warnings(warnings), nil +} + func (actor Actor) getDeployment(deploymentGUID string) (resources.Deployment, Warnings, error) { deployment, warnings, err := actor.CloudControllerClient.GetDeployment(deploymentGUID) if err != nil { @@ -444,8 +455,8 @@ func (actor Actor) RenameApplicationByNameAndSpaceGUID(appName, newAppName, spac if err != nil { return resources.Application{}, allWarnings, err } - application.Name = newAppName - application, warnings, err = actor.UpdateApplication(application) + appGUID := application.GUID + application, warnings, err = actor.UpdateApplicationName(newAppName, appGUID) allWarnings = append(allWarnings, warnings...) if err != nil { return resources.Application{}, allWarnings, err diff --git a/actor/v7action/application_test.go b/actor/v7action/application_test.go index 4d02f5c565c..e360fd5dd74 100644 --- a/actor/v7action/application_test.go +++ b/actor/v7action/application_test.go @@ -773,6 +773,76 @@ var _ = Describe("Application Actions", func() { }) }) + Describe("UpdateApplicationName", func() { + var ( + resultApp resources.Application + newAppName, appGUID string + warnings Warnings + err error + ) + + JustBeforeEach(func() { + newAppName = "some-new-app-name" + appGUID = "some-app-guid" + + resultApp, warnings, err = actor.UpdateApplicationName(newAppName, appGUID) + }) + + When("the app successfully gets updated", func() { + var apiResponseApp resources.Application + + BeforeEach(func() { + apiResponseApp = resources.Application{ + GUID: "response-app-guid", + StackName: "response-stack-name", + Name: "response-app-name", + LifecycleType: constant.AppLifecycleTypeBuildpack, + LifecycleBuildpacks: []string{"response-buildpack-1", "response-buildpack-2"}, + } + fakeCloudControllerClient.UpdateApplicationNameReturns( + apiResponseApp, + ccv3.Warnings{"some-warning"}, + nil, + ) + }) + + It("creates and returns the application and warnings", func() { + Expect(err).ToNot(HaveOccurred()) + Expect(resultApp).To(Equal(resources.Application{ + Name: apiResponseApp.Name, + GUID: apiResponseApp.GUID, + StackName: apiResponseApp.StackName, + LifecycleType: apiResponseApp.LifecycleType, + LifecycleBuildpacks: apiResponseApp.LifecycleBuildpacks, + })) + Expect(warnings).To(ConsistOf("some-warning")) + + Expect(fakeCloudControllerClient.UpdateApplicationNameCallCount()).To(Equal(1)) + appName, appGuid := fakeCloudControllerClient.UpdateApplicationNameArgsForCall(0) + Expect(appName).To(Equal("some-new-app-name")) + Expect(appGuid).To(Equal("some-app-guid")) + }) + }) + + When("the cc client returns an error", func() { + var expectedError error + + BeforeEach(func() { + expectedError = errors.New("I am a CloudControllerClient Error") + fakeCloudControllerClient.UpdateApplicationNameReturns( + resources.Application{}, + ccv3.Warnings{"some-warning"}, + expectedError, + ) + }) + + It("raises the error and warnings", func() { + Expect(err).To(MatchError(expectedError)) + Expect(warnings).To(ConsistOf("some-warning")) + }) + }) + }) + Describe("PollStart", func() { var ( app resources.Application @@ -2016,7 +2086,7 @@ var _ = Describe("Application Actions", func() { }, ccv3.Warnings{"get-app-warning"}, nil) - fakeCloudControllerClient.UpdateApplicationReturns( + fakeCloudControllerClient.UpdateApplicationNameReturns( resources.Application{}, ccv3.Warnings{"update-app-warning"}, expectedError) @@ -2042,7 +2112,7 @@ var _ = Describe("Application Actions", func() { nil, ) - fakeCloudControllerClient.UpdateApplicationReturns( + fakeCloudControllerClient.UpdateApplicationNameReturns( resources.Application{ Name: "new-app-name", GUID: "old-app-guid", @@ -2060,13 +2130,9 @@ var _ = Describe("Application Actions", func() { GUID: "old-app-guid", })) Expect(warnings).To(ConsistOf("get-app-warning", "update-app-warning")) - - Expect(fakeCloudControllerClient.UpdateApplicationArgsForCall(0)).To(Equal( - resources.Application{ - Name: "new-app-name", - GUID: "old-app-guid", - })) - + appName, appGuid := fakeCloudControllerClient.UpdateApplicationNameArgsForCall(0) + Expect(appName).To(Equal("new-app-name")) + Expect(appGuid).To(Equal("old-app-guid")) }) }) diff --git a/actor/v7action/cloud_controller_client.go b/actor/v7action/cloud_controller_client.go index 050b4d5fdac..e1f889cf7ad 100644 --- a/actor/v7action/cloud_controller_client.go +++ b/actor/v7action/cloud_controller_client.go @@ -159,6 +159,7 @@ type CloudControllerClient interface { UnshareServiceInstanceFromSpace(serviceInstanceGUID string, sharedToSpaceGUID string) (ccv3.Warnings, error) UpdateAppFeature(appGUID string, enabled bool, featureName string) (ccv3.Warnings, error) UpdateApplication(app resources.Application) (resources.Application, ccv3.Warnings, error) + UpdateApplicationName(newAppName string, appGUID string) (resources.Application, ccv3.Warnings, error) UpdateApplicationApplyManifest(appGUID string, rawManifest []byte) (ccv3.JobURL, ccv3.Warnings, error) UpdateApplicationEnvironmentVariables(appGUID string, envVars resources.EnvironmentVariables) (resources.EnvironmentVariables, ccv3.Warnings, error) UpdateApplicationRestart(appGUID string) (resources.Application, ccv3.Warnings, error) diff --git a/actor/v7action/v7actionfakes/fake_cloud_controller_client.go b/actor/v7action/v7actionfakes/fake_cloud_controller_client.go index 8b2d4240737..5511b96e84a 100644 --- a/actor/v7action/v7actionfakes/fake_cloud_controller_client.go +++ b/actor/v7action/v7actionfakes/fake_cloud_controller_client.go @@ -2271,6 +2271,22 @@ type FakeCloudControllerClient struct { result2 ccv3.Warnings result3 error } + UpdateApplicationNameStub func(string, string) (resources.Application, ccv3.Warnings, error) + updateApplicationNameMutex sync.RWMutex + updateApplicationNameArgsForCall []struct { + arg1 string + arg2 string + } + updateApplicationNameReturns struct { + result1 resources.Application + result2 ccv3.Warnings + result3 error + } + updateApplicationNameReturnsOnCall map[int]struct { + result1 resources.Application + result2 ccv3.Warnings + result3 error + } UpdateApplicationRestartStub func(string) (resources.Application, ccv3.Warnings, error) updateApplicationRestartMutex sync.RWMutex updateApplicationRestartArgsForCall []struct { @@ -12601,6 +12617,73 @@ func (fake *FakeCloudControllerClient) UpdateApplicationEnvironmentVariablesRetu }{result1, result2, result3} } +func (fake *FakeCloudControllerClient) UpdateApplicationName(arg1 string, arg2 string) (resources.Application, ccv3.Warnings, error) { + fake.updateApplicationNameMutex.Lock() + ret, specificReturn := fake.updateApplicationNameReturnsOnCall[len(fake.updateApplicationNameArgsForCall)] + fake.updateApplicationNameArgsForCall = append(fake.updateApplicationNameArgsForCall, struct { + arg1 string + arg2 string + }{arg1, arg2}) + fake.recordInvocation("UpdateApplicationName", []interface{}{arg1, arg2}) + fake.updateApplicationNameMutex.Unlock() + if fake.UpdateApplicationNameStub != nil { + return fake.UpdateApplicationNameStub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2, ret.result3 + } + fakeReturns := fake.updateApplicationNameReturns + return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 +} + +func (fake *FakeCloudControllerClient) UpdateApplicationNameCallCount() int { + fake.updateApplicationNameMutex.RLock() + defer fake.updateApplicationNameMutex.RUnlock() + return len(fake.updateApplicationNameArgsForCall) +} + +func (fake *FakeCloudControllerClient) UpdateApplicationNameCalls(stub func(string, string) (resources.Application, ccv3.Warnings, error)) { + fake.updateApplicationNameMutex.Lock() + defer fake.updateApplicationNameMutex.Unlock() + fake.UpdateApplicationNameStub = stub +} + +func (fake *FakeCloudControllerClient) UpdateApplicationNameArgsForCall(i int) (string, string) { + fake.updateApplicationNameMutex.RLock() + defer fake.updateApplicationNameMutex.RUnlock() + argsForCall := fake.updateApplicationNameArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeCloudControllerClient) UpdateApplicationNameReturns(result1 resources.Application, result2 ccv3.Warnings, result3 error) { + fake.updateApplicationNameMutex.Lock() + defer fake.updateApplicationNameMutex.Unlock() + fake.UpdateApplicationNameStub = nil + fake.updateApplicationNameReturns = struct { + result1 resources.Application + result2 ccv3.Warnings + result3 error + }{result1, result2, result3} +} + +func (fake *FakeCloudControllerClient) UpdateApplicationNameReturnsOnCall(i int, result1 resources.Application, result2 ccv3.Warnings, result3 error) { + fake.updateApplicationNameMutex.Lock() + defer fake.updateApplicationNameMutex.Unlock() + fake.UpdateApplicationNameStub = nil + if fake.updateApplicationNameReturnsOnCall == nil { + fake.updateApplicationNameReturnsOnCall = make(map[int]struct { + result1 resources.Application + result2 ccv3.Warnings + result3 error + }) + } + fake.updateApplicationNameReturnsOnCall[i] = struct { + result1 resources.Application + result2 ccv3.Warnings + result3 error + }{result1, result2, result3} +} + func (fake *FakeCloudControllerClient) UpdateApplicationRestart(arg1 string) (resources.Application, ccv3.Warnings, error) { fake.updateApplicationRestartMutex.Lock() ret, specificReturn := fake.updateApplicationRestartReturnsOnCall[len(fake.updateApplicationRestartArgsForCall)] @@ -14843,6 +14926,8 @@ func (fake *FakeCloudControllerClient) Invocations() map[string][][]interface{} defer fake.updateApplicationApplyManifestMutex.RUnlock() fake.updateApplicationEnvironmentVariablesMutex.RLock() defer fake.updateApplicationEnvironmentVariablesMutex.RUnlock() + fake.updateApplicationNameMutex.RLock() + defer fake.updateApplicationNameMutex.RUnlock() fake.updateApplicationRestartMutex.RLock() defer fake.updateApplicationRestartMutex.RUnlock() fake.updateApplicationStartMutex.RLock() diff --git a/api/cloudcontroller/ccv3/application.go b/api/cloudcontroller/ccv3/application.go index a060993253b..d4e7d56e0e2 100644 --- a/api/cloudcontroller/ccv3/application.go +++ b/api/cloudcontroller/ccv3/application.go @@ -66,6 +66,19 @@ func (client *Client) UpdateApplication(app resources.Application) (resources.Ap return responseBody, warnings, err } +// UpdateApplicationName updates an application with the new name given +func (client *Client) UpdateApplicationName(newAppName string, appGUID string) (resources.Application, Warnings, error) { + var responseBody resources.Application + _, warnings, err := client.MakeRequest(RequestParams{ + RequestName: internal.PatchApplicationRequest, + URIParams: internal.Params{"app_guid": appGUID}, + RequestBody: resources.ApplicationNameOnly{Name: newAppName}, + ResponseBody: &responseBody, + }) + + return responseBody, warnings, err +} + // UpdateApplicationRestart restarts the given application. func (client *Client) UpdateApplicationRestart(appGUID string) (resources.Application, Warnings, error) { var responseBody resources.Application diff --git a/api/cloudcontroller/ccv3/application_test.go b/api/cloudcontroller/ccv3/application_test.go index ff2bf9e4d4d..2e1ec880ffd 100644 --- a/api/cloudcontroller/ccv3/application_test.go +++ b/api/cloudcontroller/ccv3/application_test.go @@ -614,6 +614,104 @@ var _ = Describe("Application", func() { }) }) + Describe("UpdateApplicationName", func() { + var ( + newAppName string + appGUID string + + updatedApp resources.Application + warnings Warnings + executeErr error + ) + + JustBeforeEach(func() { + newAppName = "some-new-app-name" + appGUID = "some-app-guid" + + updatedApp, warnings, executeErr = client.UpdateApplicationName(newAppName, appGUID) + }) + + When("the application successfully is updated", func() { + BeforeEach(func() { + requester.MakeRequestCalls(func(requestParams RequestParams) (JobURL, Warnings, error) { + requestParams.ResponseBody.(*resources.Application).GUID = appGUID + requestParams.ResponseBody.(*resources.Application).Name = requestParams.RequestBody.(resources.ApplicationNameOnly).Name + requestParams.ResponseBody.(*resources.Application).StackName = "some-stack-name" + requestParams.ResponseBody.(*resources.Application).LifecycleType = constant.AppLifecycleTypeBuildpack + requestParams.ResponseBody.(*resources.Application).LifecycleBuildpacks = []string{"some-buildpack"} + requestParams.ResponseBody.(*resources.Application).SpaceGUID = "some-space-guid" + return "", Warnings{"this is a warning"}, nil + }) + }) + + It("makes the correct request", func() { + Expect(requester.MakeRequestCallCount()).To(Equal(1)) + actualParams := requester.MakeRequestArgsForCall(0) + Expect(actualParams.RequestName).To(Equal(internal.PatchApplicationRequest)) + Expect(actualParams.URIParams).To(Equal(internal.Params{"app_guid": "some-app-guid"})) + Expect(actualParams.RequestBody).To(Equal(resources.ApplicationNameOnly{Name: newAppName})) + _, ok := actualParams.ResponseBody.(*resources.Application) + Expect(ok).To(BeTrue()) + }) + + It("returns the updated app and warnings", func() { + Expect(executeErr).NotTo(HaveOccurred()) + Expect(warnings).To(ConsistOf("this is a warning")) + + Expect(updatedApp).To(Equal(resources.Application{ + GUID: "some-app-guid", + StackName: "some-stack-name", + LifecycleBuildpacks: []string{"some-buildpack"}, + LifecycleType: constant.AppLifecycleTypeBuildpack, + Name: "some-new-app-name", + SpaceGUID: "some-space-guid", + })) + }) + }) + + When("cc returns back an error or warnings", func() { + BeforeEach(func() { + errors := []ccerror.V3Error{ + { + Code: 10008, + Detail: "The request is semantically invalid: command presence", + Title: "CF-UnprocessableEntity", + }, + { + Code: 10010, + Detail: "App not found", + Title: "CF-ResourceNotFound", + }, + } + + requester.MakeRequestReturns( + "", + Warnings{"this is a warning"}, + ccerror.MultiError{ResponseCode: http.StatusTeapot, Errors: errors}, + ) + }) + + It("returns the error and all warnings", func() { + Expect(executeErr).To(MatchError(ccerror.MultiError{ + ResponseCode: http.StatusTeapot, + Errors: []ccerror.V3Error{ + { + Code: 10008, + Detail: "The request is semantically invalid: command presence", + Title: "CF-UnprocessableEntity", + }, + { + Code: 10010, + Detail: "App not found", + Title: "CF-ResourceNotFound", + }, + }, + })) + Expect(warnings).To(ConsistOf("this is a warning")) + }) + }) + }) + Describe("UpdateApplicationStop", func() { var ( responseApp resources.Application diff --git a/resources/application_resource.go b/resources/application_resource.go index b663ce8f8ce..361cb14c6a7 100644 --- a/resources/application_resource.go +++ b/resources/application_resource.go @@ -26,6 +26,12 @@ type Application struct { State constant.ApplicationState } +// ApplicationNameOnly represents only the name field of a Cloud Controller V3 Application +type ApplicationNameOnly struct { + // Name is the name given to the application. + Name string `json:"name,omitempty"` +} + // MarshalJSON converts an Application into a Cloud Controller Application. func (a Application) MarshalJSON() ([]byte, error) { ccApp := ccApplication{ From 3c0cb4a819b519f82b3659fb04b92f443c852404 Mon Sep 17 00:00:00 2001 From: "M. Oleske" Date: Thu, 22 Sep 2022 14:35:11 -0400 Subject: [PATCH 047/248] Use Eventually/Should for routes_command list routes with http1 and (#2324) - Existing test was flaky as the order of the two lines could change. This uses eventually/should to check the buffer in any order --- integration/v7/isolated/routes_command_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration/v7/isolated/routes_command_test.go b/integration/v7/isolated/routes_command_test.go index 73813867368..0e1c302762f 100644 --- a/integration/v7/isolated/routes_command_test.go +++ b/integration/v7/isolated/routes_command_test.go @@ -186,8 +186,8 @@ var _ = Describe("routes command", func() { Eventually(session).Should(Exit(0)) Expect(session).To(Say(`Getting routes for org %s / space %s as %s\.\.\.`, orgName, spaceName, userName)) Expect(session).To(Say(tableHeaders)) - Expect(session).To(Say(`%s\s+route1\s+%s\s+http\s+http1, http2\s+%s\s+\n`, spaceName, domainName, fmt.Sprintf("%s, %s", appName1, appName2))) - Expect(session).To(Say(`%s\s+route2\s+%s\s+http\s+http1\s+%s\s+\n`, spaceName, domainName, appName2)) + Eventually(session).Should(Say(`%s\s+route1\s+%s\s+http\s+http1, http2\s+%s\s+\n`, spaceName, domainName, fmt.Sprintf("%s, %s", appName1, appName2))) + Eventually(session).Should(Say(`%s\s+route2\s+%s\s+http\s+http1\s+%s\s+\n`, spaceName, domainName, appName2)) }) }) From d115c061764a17d5f59ec8dae45b71cba67eca88 Mon Sep 17 00:00:00 2001 From: MerricdeLauney Date: Tue, 25 Oct 2022 08:23:05 -0700 Subject: [PATCH 048/248] Implement unshare route command (#2328) - Implements cf unshare-routte Co-authored-by: Merric de Launey Co-authored-by: David Alvarado --- actor/v7action/cloud_controller_client.go | 1 + actor/v7action/route.go | 5 + actor/v7action/route_test.go | 40 +++ .../fake_cloud_controller_client.go | 80 +++++ .../ccv3/internal/api_routes.go | 2 + api/cloudcontroller/ccv3/route.go | 11 + api/cloudcontroller/ccv3/route_test.go | 78 +++++ command/common/command_list_v7.go | 1 + command/common/internal/help_all_display.go | 2 +- command/v7/actor.go | 1 + command/v7/share_route_command.go | 4 +- command/v7/unshare_route_command.go | 101 +++++++ command/v7/unshare_route_command_test.go | 280 ++++++++++++++++++ command/v7/v7fakes/fake_actor.go | 80 +++++ .../v7/isolated/share_route_command_test.go | 4 +- .../v7/isolated/unshare_route_command_test.go | 209 +++++++++++++ 16 files changed, 894 insertions(+), 5 deletions(-) create mode 100644 command/v7/unshare_route_command.go create mode 100644 command/v7/unshare_route_command_test.go create mode 100644 integration/v7/isolated/unshare_route_command_test.go diff --git a/actor/v7action/cloud_controller_client.go b/actor/v7action/cloud_controller_client.go index e1f889cf7ad..e855e9624f5 100644 --- a/actor/v7action/cloud_controller_client.go +++ b/actor/v7action/cloud_controller_client.go @@ -155,6 +155,7 @@ type CloudControllerClient interface { UnbindSecurityGroupRunningSpace(securityGroupGUID string, spaceGUID string) (ccv3.Warnings, error) UnbindSecurityGroupStagingSpace(securityGroupGUID string, spaceGUID string) (ccv3.Warnings, error) UnmapRoute(routeGUID string, destinationGUID string) (ccv3.Warnings, error) + UnshareRoute(routeGUID string, spaceGUID string) (ccv3.Warnings, error) UnsharePrivateDomainFromOrg(domainGUID string, sharedOrgGUID string) (ccv3.Warnings, error) UnshareServiceInstanceFromSpace(serviceInstanceGUID string, sharedToSpaceGUID string) (ccv3.Warnings, error) UpdateAppFeature(appGUID string, enabled bool, featureName string) (ccv3.Warnings, error) diff --git a/actor/v7action/route.go b/actor/v7action/route.go index 7cac6180001..e3da624d425 100644 --- a/actor/v7action/route.go +++ b/actor/v7action/route.go @@ -410,6 +410,11 @@ func (actor Actor) ShareRoute(routeGUID string, spaceGUID string) (Warnings, err warnings, err := actor.CloudControllerClient.ShareRoute(routeGUID, spaceGUID) return Warnings(warnings), err } + +func (actor Actor) UnshareRoute(routeGUID string, spaceGUID string) (Warnings, error) { + warnings, err := actor.CloudControllerClient.UnshareRoute(routeGUID, spaceGUID) + return Warnings(warnings), err +} func (actor Actor) GetApplicationRoutes(appGUID string) ([]resources.Route, Warnings, error) { allWarnings := Warnings{} diff --git a/actor/v7action/route_test.go b/actor/v7action/route_test.go index 56381a0032f..3feacd6e5ba 100644 --- a/actor/v7action/route_test.go +++ b/actor/v7action/route_test.go @@ -1590,6 +1590,46 @@ var _ = Describe("Route Actions", func() { }) }) + Describe("UnshareRoute", func() { + var ( + routeGUID string + spaceGUID string + + executeErr error + warnings Warnings + ) + + JustBeforeEach(func() { + warnings, executeErr = actor.UnshareRoute(routeGUID, spaceGUID) + }) + + BeforeEach(func() { + routeGUID = "route-guid" + spaceGUID = "space-guid" + }) + + When("the cloud controller client errors", func() { + BeforeEach(func() { + fakeCloudControllerClient.UnshareRouteReturns(ccv3.Warnings{"unshare-route-warning"}, errors.New("unshare-route-error")) + }) + + It("returns the error and warnings", func() { + Expect(executeErr).To(MatchError(errors.New("unshare-route-error"))) + Expect(warnings).To(ConsistOf("unshare-route-warning")) + }) + }) + + When("the cloud controller client succeeds", func() { + BeforeEach(func() { + fakeCloudControllerClient.UnshareRouteReturns(ccv3.Warnings{"unshare-route-warning"}, nil) + }) + + It("returns the warnings", func() { + Expect(executeErr).ToNot(HaveOccurred()) + Expect(warnings).To(ConsistOf("unshare-route-warning")) + }) + }) + }) Describe("UnmapRoute", func() { var ( routeGUID string diff --git a/actor/v7action/v7actionfakes/fake_cloud_controller_client.go b/actor/v7action/v7actionfakes/fake_cloud_controller_client.go index 5511b96e84a..e2ff9883854 100644 --- a/actor/v7action/v7actionfakes/fake_cloud_controller_client.go +++ b/actor/v7action/v7actionfakes/fake_cloud_controller_client.go @@ -2195,6 +2195,20 @@ type FakeCloudControllerClient struct { result1 ccv3.Warnings result2 error } + UnshareRouteStub func(string, string) (ccv3.Warnings, error) + unshareRouteMutex sync.RWMutex + unshareRouteArgsForCall []struct { + arg1 string + arg2 string + } + unshareRouteReturns struct { + result1 ccv3.Warnings + result2 error + } + unshareRouteReturnsOnCall map[int]struct { + result1 ccv3.Warnings + result2 error + } UnshareServiceInstanceFromSpaceStub func(string, string) (ccv3.Warnings, error) unshareServiceInstanceFromSpaceMutex sync.RWMutex unshareServiceInstanceFromSpaceArgsForCall []struct { @@ -12283,6 +12297,70 @@ func (fake *FakeCloudControllerClient) UnsharePrivateDomainFromOrgReturnsOnCall( }{result1, result2} } +func (fake *FakeCloudControllerClient) UnshareRoute(arg1 string, arg2 string) (ccv3.Warnings, error) { + fake.unshareRouteMutex.Lock() + ret, specificReturn := fake.unshareRouteReturnsOnCall[len(fake.unshareRouteArgsForCall)] + fake.unshareRouteArgsForCall = append(fake.unshareRouteArgsForCall, struct { + arg1 string + arg2 string + }{arg1, arg2}) + fake.recordInvocation("UnshareRoute", []interface{}{arg1, arg2}) + fake.unshareRouteMutex.Unlock() + if fake.UnshareRouteStub != nil { + return fake.UnshareRouteStub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.unshareRouteReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeCloudControllerClient) UnshareRouteCallCount() int { + fake.unshareRouteMutex.RLock() + defer fake.unshareRouteMutex.RUnlock() + return len(fake.unshareRouteArgsForCall) +} + +func (fake *FakeCloudControllerClient) UnshareRouteCalls(stub func(string, string) (ccv3.Warnings, error)) { + fake.unshareRouteMutex.Lock() + defer fake.unshareRouteMutex.Unlock() + fake.UnshareRouteStub = stub +} + +func (fake *FakeCloudControllerClient) UnshareRouteArgsForCall(i int) (string, string) { + fake.unshareRouteMutex.RLock() + defer fake.unshareRouteMutex.RUnlock() + argsForCall := fake.unshareRouteArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeCloudControllerClient) UnshareRouteReturns(result1 ccv3.Warnings, result2 error) { + fake.unshareRouteMutex.Lock() + defer fake.unshareRouteMutex.Unlock() + fake.UnshareRouteStub = nil + fake.unshareRouteReturns = struct { + result1 ccv3.Warnings + result2 error + }{result1, result2} +} + +func (fake *FakeCloudControllerClient) UnshareRouteReturnsOnCall(i int, result1 ccv3.Warnings, result2 error) { + fake.unshareRouteMutex.Lock() + defer fake.unshareRouteMutex.Unlock() + fake.UnshareRouteStub = nil + if fake.unshareRouteReturnsOnCall == nil { + fake.unshareRouteReturnsOnCall = make(map[int]struct { + result1 ccv3.Warnings + result2 error + }) + } + fake.unshareRouteReturnsOnCall[i] = struct { + result1 ccv3.Warnings + result2 error + }{result1, result2} +} + func (fake *FakeCloudControllerClient) UnshareServiceInstanceFromSpace(arg1 string, arg2 string) (ccv3.Warnings, error) { fake.unshareServiceInstanceFromSpaceMutex.Lock() ret, specificReturn := fake.unshareServiceInstanceFromSpaceReturnsOnCall[len(fake.unshareServiceInstanceFromSpaceArgsForCall)] @@ -14916,6 +14994,8 @@ func (fake *FakeCloudControllerClient) Invocations() map[string][][]interface{} defer fake.unsetSpaceQuotaMutex.RUnlock() fake.unsharePrivateDomainFromOrgMutex.RLock() defer fake.unsharePrivateDomainFromOrgMutex.RUnlock() + fake.unshareRouteMutex.RLock() + defer fake.unshareRouteMutex.RUnlock() fake.unshareServiceInstanceFromSpaceMutex.RLock() defer fake.unshareServiceInstanceFromSpaceMutex.RUnlock() fake.updateAppFeatureMutex.RLock() diff --git a/api/cloudcontroller/ccv3/internal/api_routes.go b/api/cloudcontroller/ccv3/internal/api_routes.go index 5da806e7d29..1e747e21033 100644 --- a/api/cloudcontroller/ccv3/internal/api_routes.go +++ b/api/cloudcontroller/ccv3/internal/api_routes.go @@ -175,6 +175,7 @@ const ( SharePrivateDomainRequest = "SharePrivateDomainRequest" ShareRouteRequest = "ShareRouteRequest" UnmapRouteRequest = "UnmapRoute" + UnshareRouteRequest = "UnshareRoute" WhoAmI = "WhoAmI" ) @@ -280,6 +281,7 @@ var APIRoutes = map[string]Route{ UnmapRouteRequest: {Path: "/v3/routes/:route_guid/destinations/:destination_guid", Method: http.MethodDelete}, PatchDestinationRequest: {Path: "/v3/routes/:route_guid/destinations/:destination_guid", Method: http.MethodPatch}, ShareRouteRequest: {Path: "/v3/routes/:route_guid/relationships/shared_spaces", Method: http.MethodPost}, + UnshareRouteRequest: {Path: "/v3/routes/:route_guid/relationships/shared_spaces/:space_guid", Method: http.MethodDelete}, PatchMoveRouteRequest: {Path: "/v3/routes/:route_guid/relationships/space", Method: http.MethodPatch}, GetSecurityGroupsRequest: {Path: "/v3/security_groups", Method: http.MethodGet}, PostSecurityGroupRequest: {Path: "/v3/security_groups", Method: http.MethodPost}, diff --git a/api/cloudcontroller/ccv3/route.go b/api/cloudcontroller/ccv3/route.go index 56f068640a6..afff0af5e9a 100644 --- a/api/cloudcontroller/ccv3/route.go +++ b/api/cloudcontroller/ccv3/route.go @@ -132,6 +132,17 @@ func (client Client) UnmapRoute(routeGUID string, destinationGUID string) (Warni return warnings, err } +func (client Client) UnshareRoute(routeGUID string, spaceGUID string) (Warnings, error) { + var responseBody resources.Build + + _, warnings, err := client.MakeRequest(RequestParams{ + RequestName: internal.UnshareRouteRequest, + URIParams: internal.Params{"route_guid": routeGUID, "space_guid": spaceGUID}, + ResponseBody: &responseBody, + }) + return warnings, err +} + func (client Client) UpdateDestination(routeGUID string, destinationGUID string, protocol string) (Warnings, error) { type body struct { Protocol string `json:"protocol"` diff --git a/api/cloudcontroller/ccv3/route_test.go b/api/cloudcontroller/ccv3/route_test.go index 1ef7b6d2c5b..3e6f5e9a0da 100644 --- a/api/cloudcontroller/ccv3/route_test.go +++ b/api/cloudcontroller/ccv3/route_test.go @@ -798,6 +798,84 @@ var _ = Describe("Route", func() { }) }) + Describe("UnshareRoute", func() { + var ( + routeGUID string + spaceGUID string + warnings Warnings + executeErr error + ) + + JustBeforeEach(func() { + warnings, executeErr = client.UnshareRoute(routeGUID, spaceGUID) + }) + + When("aroute exists and is shared with the space", func() { + routeGUID = "route-guid" + spaceGUID = "space-guid" + + BeforeEach(func() { + server.AppendHandlers( + CombineHandlers( + VerifyRequest(http.MethodDelete, "/v3/routes/route-guid/relationships/shared_spaces/space-guid"), + RespondWith(http.StatusNoContent, nil, http.Header{ + "X-Cf-Warnings": {"this is a warning"}, + }), + ), + ) + }) + + It("returns warnings", func() { + Expect(executeErr).NotTo(HaveOccurred()) + Expect(warnings).To(ConsistOf("this is a warning")) + }) + }) + + When("the cloud controller returns errors and warnings", func() { + BeforeEach(func() { + response := `{ + "errors": [ + { + "code": 10008, + "detail": "The request is semantically invalid: command presence", + "title": "CF-UnprocessableEntity" + }, + { + "code": 10010, + "detail": "Route not found", + "title": "CF-ResourceNotFound" + } + ] + }` + server.AppendHandlers( + CombineHandlers( + VerifyRequest(http.MethodDelete, "/v3/routes/route-guid/relationships/shared_spaces/space-guid"), + RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), + ), + ) + }) + + It("returns the error and all warnings", func() { + Expect(executeErr).To(MatchError(ccerror.MultiError{ + ResponseCode: http.StatusTeapot, + Errors: []ccerror.V3Error{ + { + Code: 10008, + Detail: "The request is semantically invalid: command presence", + Title: "CF-UnprocessableEntity", + }, + { + Code: 10010, + Detail: "Route not found", + Title: "CF-ResourceNotFound", + }, + }, + })) + Expect(warnings).To(ConsistOf("this is a warning")) + }) + }) + }) + Describe("UpdateDestination", func() { var ( routeGUID string diff --git a/command/common/command_list_v7.go b/command/common/command_list_v7.go index 3a2b660f3bd..2e1bc07ea5e 100644 --- a/command/common/command_list_v7.go +++ b/command/common/command_list_v7.go @@ -187,6 +187,7 @@ type commandList struct { UnsetSpaceQuota v7.UnsetSpaceQuotaCommand `command:"unset-space-quota" description:"Unassign a quota from a space"` UnsetSpaceRole v7.UnsetSpaceRoleCommand `command:"unset-space-role" description:"Remove a space role from a user"` UnsharePrivateDomain v7.UnsharePrivateDomainCommand `command:"unshare-private-domain" description:"Unshare a private domain with a specific org"` + UnshareRoute v7.UnshareRouteCommand `command:"unshare-route" description:"Unshare an existing route from a space"` UnshareService v7.UnshareServiceCommand `command:"unshare-service" description:"Unshare a shared service instance from a space"` UpdateBuildpack v7.UpdateBuildpackCommand `command:"update-buildpack" description:"Update a buildpack"` UpdateDestination v7.UpdateDestinationCommand `command:"update-destination" description:"Updates the destination protocol for a route"` diff --git a/command/common/internal/help_all_display.go b/command/common/internal/help_all_display.go index 97990a5002d..738f496672e 100644 --- a/command/common/internal/help_all_display.go +++ b/command/common/internal/help_all_display.go @@ -68,7 +68,7 @@ var HelpCategoryList = []HelpCategory{ {"create-route", "check-route", "map-route", "unmap-route", "delete-route"}, {"delete-orphaned-routes"}, {"update-destination"}, - {"share-route"}, + {"share-route", "unshare-route"}, {"move-route"}, }, }, diff --git a/command/v7/actor.go b/command/v7/actor.go index 3bbae507c69..5559246c591 100644 --- a/command/v7/actor.go +++ b/command/v7/actor.go @@ -228,6 +228,7 @@ type Actor interface { UnsetEnvironmentVariableByApplicationNameAndSpace(appName string, spaceGUID string, EnvironmentVariableName string) (v7action.Warnings, error) UnsetSpaceQuota(spaceQuotaName, spaceName, orgGUID string) (v7action.Warnings, error) UnsharePrivateDomain(domainName string, orgName string) (v7action.Warnings, error) + UnshareRoute(routeGUID string, spaceGUID string) (v7action.Warnings, error) UnshareServiceInstanceFromSpaceAndOrg(serviceInstanceName, targetedSpaceGUID, targetedOrgGUID string, unshareFromDetails v7action.ServiceInstanceSharingParams) (v7action.Warnings, error) UpdateAppFeature(app resources.Application, enabled bool, featureName string) (v7action.Warnings, error) UpdateApplication(app resources.Application) (resources.Application, v7action.Warnings, error) diff --git a/command/v7/share_route_command.go b/command/v7/share_route_command.go index b1fdb2b6880..8f36268da50 100644 --- a/command/v7/share_route_command.go +++ b/command/v7/share_route_command.go @@ -11,8 +11,8 @@ type ShareRouteCommand struct { RequireArgs flag.Domain `positional-args:"yes"` Hostname string `long:"hostname" short:"n" description:"Hostname for the HTTP route (required for shared domains)"` Path flag.V7RoutePath `long:"path" description:"Path for the HTTP route"` - DestinationOrg string `short:"o" description:"The org of the destination app (Default: targeted org)"` - DestinationSpace string `short:"s" description:"The space of the destination app (Default: targeted space)"` + DestinationOrg string `short:"o" description:"The org of the destination space (Default: targeted org)"` + DestinationSpace string `short:"s" description:"The space the route will be shared with (Default: targeted space)"` relatedCommands interface{} `related_commands:"create-route, map-route, unmap-route, routes"` } diff --git a/command/v7/unshare_route_command.go b/command/v7/unshare_route_command.go new file mode 100644 index 00000000000..c25934b9746 --- /dev/null +++ b/command/v7/unshare_route_command.go @@ -0,0 +1,101 @@ +package v7 + +import ( + "code.cloudfoundry.org/cli/actor/actionerror" + "code.cloudfoundry.org/cli/command/flag" +) + +type UnshareRouteCommand struct { + BaseCommand + + RequireArgs flag.Domain `positional-args:"yes"` + Hostname string `long:"hostname" short:"n" description:"Hostname for the HTTP route (required for shared domains)"` + Path flag.V7RoutePath `long:"path" description:"Path for the HTTP route"` + DestinationOrg string `short:"o" description:"The org of the destination space (Default: targeted org)"` + DestinationSpace string `short:"s" description:"The space to be unshared (Default: targeted space)"` + + relatedCommands interface{} `related_commands:" share-route, delete-route, map-route, unmap-route, routes"` +} + +func (cmd UnshareRouteCommand) Usage() string { + return ` +Unshare an existing route from a space: + CF_NAME unshare-route DOMAIN [--hostname HOSTNAME] [--path PATH] -s OTHER_SPACE [-o OTHER_ORG]` +} + +func (cmd UnshareRouteCommand) Examples() string { + return ` +CF_NAME unshare-route example.com --hostname myHost --path foo -s TargetSpace -o TargetOrg # myhost.example.com/foo +CF_NAME unshare-route example.com --hostname myHost -s TargetSpace # myhost.example.com +CF_NAME unshare-route example.com --hostname myHost -s TargetSpace -o TargetOrg # myhost.example.com` +} + +func (cmd UnshareRouteCommand) Execute(args []string) error { + err := cmd.SharedActor.CheckTarget(true, true) + if err != nil { + return err + } + + user, err := cmd.Actor.GetCurrentUser() + if err != nil { + return err + } + + domain, warnings, err := cmd.Actor.GetDomainByName(cmd.RequireArgs.Domain) + cmd.UI.DisplayWarnings(warnings) + if err != nil { + return err + } + + path := cmd.Path.Path + route, warnings, err := cmd.Actor.GetRouteByAttributes(domain, cmd.Hostname, path, 0) + cmd.UI.DisplayWarnings(warnings) + if err != nil { + if _, ok := err.(actionerror.RouteNotFoundError); ok { + cmd.UI.DisplayText("Can not unshare route:") + return err + } + } + + destinationOrgName := cmd.DestinationOrg + + if destinationOrgName == "" { + destinationOrgName = cmd.Config.TargetedOrganizationName() + } + + destinationOrg, warnings, err := cmd.Actor.GetOrganizationByName(destinationOrgName) + + if err != nil { + if _, ok := err.(actionerror.OrganizationNotFoundError); ok { + cmd.UI.DisplayText("Can not unshare route:") + return err + } + } + + targetedSpace, warnings, err := cmd.Actor.GetSpaceByNameAndOrganization(cmd.DestinationSpace, destinationOrg.GUID) + if err != nil { + if _, ok := err.(actionerror.SpaceNotFoundError); ok { + cmd.UI.DisplayText("Can not unshare route:") + return err + } + } + + url := desiredURL(domain.Name, cmd.Hostname, path, 0) + cmd.UI.DisplayTextWithFlavor("Unsharing route {{.URL}} from space {{.DestinationSpace}} as {{.User}}", + map[string]interface{}{ + "URL": url, + "DestinationSpace": cmd.DestinationSpace, + "User": user.Name, + }) + warnings, err = cmd.Actor.UnshareRoute( + route.GUID, + targetedSpace.GUID, + ) + cmd.UI.DisplayWarnings(warnings) + if err != nil { + return err + } + cmd.UI.DisplayOK() + + return nil +} diff --git a/command/v7/unshare_route_command_test.go b/command/v7/unshare_route_command_test.go new file mode 100644 index 00000000000..b3237815755 --- /dev/null +++ b/command/v7/unshare_route_command_test.go @@ -0,0 +1,280 @@ +package v7_test + +import ( + "errors" + + "code.cloudfoundry.org/cli/actor/actionerror" + "code.cloudfoundry.org/cli/actor/v7action" + "code.cloudfoundry.org/cli/command/commandfakes" + "code.cloudfoundry.org/cli/command/flag" + v7 "code.cloudfoundry.org/cli/command/v7" + "code.cloudfoundry.org/cli/command/v7/v7fakes" + "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/util/configv3" + "code.cloudfoundry.org/cli/util/ui" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gbytes" +) + +var _ = Describe("unshare-route Command", func() { + var ( + cmd v7.UnshareRouteCommand + testUI *ui.UI + fakeConfig *commandfakes.FakeConfig + fakeSharedActor *commandfakes.FakeSharedActor + fakeActor *v7fakes.FakeActor + binaryName string + executeErr error + domainName string + orgName string + spaceName string + hostname string + path string + ) + + BeforeEach(func() { + testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) + fakeConfig = new(commandfakes.FakeConfig) + fakeSharedActor = new(commandfakes.FakeSharedActor) + fakeActor = new(v7fakes.FakeActor) + + binaryName = "myBinaryBread" + fakeConfig.BinaryNameReturns(binaryName) + + domainName = "some-domain.com" + orgName = "org-name-a" + spaceName = "space-name-a" + hostname = "myHostname" + path = "myPath" + + cmd = v7.UnshareRouteCommand{ + BaseCommand: v7.BaseCommand{ + UI: testUI, + Config: fakeConfig, + SharedActor: fakeSharedActor, + Actor: fakeActor, + }, + RequireArgs: flag.Domain{Domain: domainName}, + Hostname: hostname, + Path: flag.V7RoutePath{Path: path}, + DestinationOrg: orgName, + DestinationSpace: spaceName, + } + + fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "some-space", GUID: "some-space-guid"}) + fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org"}) + fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) + }) + + JustBeforeEach(func() { + executeErr = cmd.Execute(nil) + }) + + It("checks that target", func() { + Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) + checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) + Expect(checkTargetedOrg).To(BeTrue()) + Expect(checkTargetedSpace).To(BeTrue()) + }) + + When("checking target fails", func() { + BeforeEach(func() { + fakeSharedActor.CheckTargetReturns(actionerror.NoOrganizationTargetedError{BinaryName: binaryName}) + }) + It("returns an error", func() { + Expect(executeErr).To(MatchError(actionerror.NoOrganizationTargetedError{BinaryName: binaryName})) + + Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) + checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) + Expect(checkTargetedOrg).To(BeTrue()) + Expect(checkTargetedSpace).To(BeTrue()) + }) + }) + + When("the user is not logged in", func() { + var expectedErr error + + BeforeEach(func() { + expectedErr = errors.New("some current user error") + fakeActor.GetCurrentUserReturns(configv3.User{}, expectedErr) + }) + + It("return an error", func() { + Expect(executeErr).To(Equal(expectedErr)) + }) + }) + + When("the user is logged in and targeted", func() { + When("getting the domain errors", func() { + BeforeEach(func() { + fakeActor.GetDomainByNameReturns(resources.Domain{}, v7action.Warnings{"get-domain-warnings"}, errors.New("get-domain-error")) + }) + + It("returns the error and displays warnings", func() { + Expect(testUI.Err).To(Say("get-domain-warnings")) + Expect(executeErr).To(MatchError(errors.New("get-domain-error"))) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(0)) + + Expect(fakeActor.GetSpaceByNameAndOrganizationCallCount()).To(Equal(0)) + + Expect(fakeActor.UnshareRouteCallCount()).To(Equal(0)) + }) + }) + + When("getting the domain succeeds", func() { + BeforeEach(func() { + fakeActor.GetDomainByNameReturns( + resources.Domain{Name: domainName, GUID: "domain-guid"}, + v7action.Warnings{"get-domain-warnings"}, + nil, + ) + }) + + When("the requested route does not exist", func() { + BeforeEach(func() { + fakeActor.GetRouteByAttributesReturns( + resources.Route{}, + v7action.Warnings{"get-route-warnings"}, + actionerror.RouteNotFoundError{}, + ) + }) + + It("displays error message", func() { + Expect(testUI.Err).To(Say("get-domain-warnings")) + Expect(testUI.Err).To(Say("get-route-warnings")) + Expect(executeErr).To(HaveOccurred()) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + }) + }) + + When("the requested route exists", func() { + BeforeEach(func() { + fakeActor.GetRouteByAttributesReturns( + resources.Route{GUID: "route-guid"}, + v7action.Warnings{"get-route-warnings"}, + nil, + ) + }) + When("getting the target space errors", func() { + BeforeEach(func() { + fakeActor.GetOrganizationByNameReturns( + resources.Organization{GUID: "org-guid-a"}, + v7action.Warnings{"get-route-warnings"}, + nil, + ) + fakeActor.GetSpaceByNameAndOrganizationReturns( + resources.Space{}, + v7action.Warnings{"get-route-warnings"}, + actionerror.SpaceNotFoundError{}, + ) + }) + It("returns the error and warnings", func() { + Expect(executeErr).To(HaveOccurred()) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + + Expect(fakeActor.GetOrganizationByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetOrganizationByNameArgsForCall(0)).To(Equal(orgName)) + Expect(fakeActor.GetSpaceByNameAndOrganizationCallCount()).To(Equal(1)) + spaceName, orgGuid := fakeActor.GetSpaceByNameAndOrganizationArgsForCall(0) + Expect(spaceName).To(Equal("space-name-a")) + Expect(orgGuid).To(Equal("org-guid-a")) + + Expect(fakeActor.UnshareRouteCallCount()).To(Equal(0)) + }) + }) + When("getting the target org errors", func() { + BeforeEach(func() { + fakeActor.GetOrganizationByNameReturns( + resources.Organization{}, + v7action.Warnings{"get-route-warnings"}, + actionerror.OrganizationNotFoundError{}, + ) + }) + It("returns the error and warnings", func() { + Expect(executeErr).To(HaveOccurred()) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + + Expect(fakeActor.GetOrganizationByNameCallCount()).To(Equal(1)) + orgName := fakeActor.GetOrganizationByNameArgsForCall(0) + Expect(orgName).To(Equal("org-name-a")) + + Expect(fakeActor.UnshareRouteCallCount()).To(Equal(0)) + }) + }) + When("getting the target space succeeds", func() { + BeforeEach(func() { + fakeActor.GetOrganizationByNameReturns( + resources.Organization{GUID: "org-guid-a"}, + v7action.Warnings{"get-route-warnings"}, + nil, + ) + fakeActor.GetSpaceByNameAndOrganizationReturns( + resources.Space{GUID: "space-guid-b"}, + v7action.Warnings{"get-route-warnings"}, + nil, + ) + }) + It("exits 0 with helpful message that the route is now being unshared", func() { + Expect(executeErr).ShouldNot(HaveOccurred()) + + Expect(fakeActor.GetDomainByNameCallCount()).To(Equal(1)) + Expect(fakeActor.GetDomainByNameArgsForCall(0)).To(Equal(domainName)) + + Expect(fakeActor.GetRouteByAttributesCallCount()).To(Equal(1)) + actualDomain, actualHostname, actualPath, actualPort := fakeActor.GetRouteByAttributesArgsForCall(0) + Expect(actualDomain.Name).To(Equal(domainName)) + Expect(actualDomain.GUID).To(Equal("domain-guid")) + Expect(actualHostname).To(Equal(hostname)) + Expect(actualPath).To(Equal(path)) + Expect(actualPort).To(Equal(0)) + + Expect(fakeActor.GetOrganizationByNameCallCount()).To(Equal(1)) + orgName := fakeActor.GetOrganizationByNameArgsForCall(0) + Expect(orgName).To(Equal("org-name-a")) + + Expect(fakeActor.GetSpaceByNameAndOrganizationCallCount()).To(Equal(1)) + spaceName, orgGuid := fakeActor.GetSpaceByNameAndOrganizationArgsForCall(0) + Expect(spaceName).To(Equal("space-name-a")) + Expect(orgGuid).To(Equal("org-guid-a")) + Expect(fakeActor.UnshareRouteCallCount()).To(Equal(1)) + }) + }) + }) + }) + }) +}) diff --git a/command/v7/v7fakes/fake_actor.go b/command/v7/v7fakes/fake_actor.go index f3cddabd4f7..f6684c33183 100644 --- a/command/v7/v7fakes/fake_actor.go +++ b/command/v7/v7fakes/fake_actor.go @@ -3148,6 +3148,20 @@ type FakeActor struct { result1 v7action.Warnings result2 error } + UnshareRouteStub func(string, string) (v7action.Warnings, error) + unshareRouteMutex sync.RWMutex + unshareRouteArgsForCall []struct { + arg1 string + arg2 string + } + unshareRouteReturns struct { + result1 v7action.Warnings + result2 error + } + unshareRouteReturnsOnCall map[int]struct { + result1 v7action.Warnings + result2 error + } UnshareServiceInstanceFromSpaceAndOrgStub func(string, string, string, v7action.ServiceInstanceSharingParams) (v7action.Warnings, error) unshareServiceInstanceFromSpaceAndOrgMutex sync.RWMutex unshareServiceInstanceFromSpaceAndOrgArgsForCall []struct { @@ -17115,6 +17129,70 @@ func (fake *FakeActor) UnsharePrivateDomainReturnsOnCall(i int, result1 v7action }{result1, result2} } +func (fake *FakeActor) UnshareRoute(arg1 string, arg2 string) (v7action.Warnings, error) { + fake.unshareRouteMutex.Lock() + ret, specificReturn := fake.unshareRouteReturnsOnCall[len(fake.unshareRouteArgsForCall)] + fake.unshareRouteArgsForCall = append(fake.unshareRouteArgsForCall, struct { + arg1 string + arg2 string + }{arg1, arg2}) + fake.recordInvocation("UnshareRoute", []interface{}{arg1, arg2}) + fake.unshareRouteMutex.Unlock() + if fake.UnshareRouteStub != nil { + return fake.UnshareRouteStub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.unshareRouteReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeActor) UnshareRouteCallCount() int { + fake.unshareRouteMutex.RLock() + defer fake.unshareRouteMutex.RUnlock() + return len(fake.unshareRouteArgsForCall) +} + +func (fake *FakeActor) UnshareRouteCalls(stub func(string, string) (v7action.Warnings, error)) { + fake.unshareRouteMutex.Lock() + defer fake.unshareRouteMutex.Unlock() + fake.UnshareRouteStub = stub +} + +func (fake *FakeActor) UnshareRouteArgsForCall(i int) (string, string) { + fake.unshareRouteMutex.RLock() + defer fake.unshareRouteMutex.RUnlock() + argsForCall := fake.unshareRouteArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeActor) UnshareRouteReturns(result1 v7action.Warnings, result2 error) { + fake.unshareRouteMutex.Lock() + defer fake.unshareRouteMutex.Unlock() + fake.UnshareRouteStub = nil + fake.unshareRouteReturns = struct { + result1 v7action.Warnings + result2 error + }{result1, result2} +} + +func (fake *FakeActor) UnshareRouteReturnsOnCall(i int, result1 v7action.Warnings, result2 error) { + fake.unshareRouteMutex.Lock() + defer fake.unshareRouteMutex.Unlock() + fake.UnshareRouteStub = nil + if fake.unshareRouteReturnsOnCall == nil { + fake.unshareRouteReturnsOnCall = make(map[int]struct { + result1 v7action.Warnings + result2 error + }) + } + fake.unshareRouteReturnsOnCall[i] = struct { + result1 v7action.Warnings + result2 error + }{result1, result2} +} + func (fake *FakeActor) UnshareServiceInstanceFromSpaceAndOrg(arg1 string, arg2 string, arg3 string, arg4 v7action.ServiceInstanceSharingParams) (v7action.Warnings, error) { fake.unshareServiceInstanceFromSpaceAndOrgMutex.Lock() ret, specificReturn := fake.unshareServiceInstanceFromSpaceAndOrgReturnsOnCall[len(fake.unshareServiceInstanceFromSpaceAndOrgArgsForCall)] @@ -19494,6 +19572,8 @@ func (fake *FakeActor) Invocations() map[string][][]interface{} { defer fake.unsetSpaceQuotaMutex.RUnlock() fake.unsharePrivateDomainMutex.RLock() defer fake.unsharePrivateDomainMutex.RUnlock() + fake.unshareRouteMutex.RLock() + defer fake.unshareRouteMutex.RUnlock() fake.unshareServiceInstanceFromSpaceAndOrgMutex.RLock() defer fake.unshareServiceInstanceFromSpaceAndOrgMutex.RUnlock() fake.updateAppFeatureMutex.RLock() diff --git a/integration/v7/isolated/share_route_command_test.go b/integration/v7/isolated/share_route_command_test.go index d3f8affe88b..68cbc538bcb 100644 --- a/integration/v7/isolated/share_route_command_test.go +++ b/integration/v7/isolated/share_route_command_test.go @@ -39,8 +39,8 @@ var _ = Describe("share route command", func() { Eventually(session).Should(Say(`OPTIONS:`)) Eventually(session).Should(Say(`--hostname, -n\s+Hostname for the HTTP route \(required for shared domains\)`)) Eventually(session).Should(Say(`--path\s+Path for the HTTP route`)) - Eventually(session).Should(Say(`-o\s+The org of the destination app \(Default: targeted org\)`)) - Eventually(session).Should(Say(`-s\s+The space of the destination app \(Default: targeted space\)`)) + Eventually(session).Should(Say(`-o\s+The org of the destination space \(Default: targeted org\)`)) + Eventually(session).Should(Say(`-s\s+The space the route will be shared with \(Default: targeted space\)`)) Eventually(session).Should(Say(`\n`)) Eventually(session).Should(Say(`SEE ALSO:`)) diff --git a/integration/v7/isolated/unshare_route_command_test.go b/integration/v7/isolated/unshare_route_command_test.go new file mode 100644 index 00000000000..b58260bd0f4 --- /dev/null +++ b/integration/v7/isolated/unshare_route_command_test.go @@ -0,0 +1,209 @@ +package isolated + +import ( + "fmt" + + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" + . "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers" + "code.cloudfoundry.org/cli/integration/helpers" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gbytes" + . "github.com/onsi/gomega/gexec" +) + +var _ = Describe("unshare route command", func() { + Context("Help", func() { + It("appears in cf help -a", func() { + session := helpers.CF("help", "-a") + + fmt.Println(session) + + Eventually(session).Should(Exit(0)) + Expect(session).To(HaveCommandInCategoryWithDescription("unshare-route", "ROUTES", "Unshare an existing route from a space")) + }) + + It("displays the help information", func() { + session := helpers.CF("unshare-route", "--help") + Eventually(session).Should(Say(`NAME:`)) + Eventually(session).Should(Say("unshare-route - Unshare an existing route from a space")) + Eventually(session).Should(Say(`\n`)) + + Eventually(session).Should(Say(`USAGE:`)) + Eventually(session).Should(Say(`Unshare an existing route from a space:`)) + Eventually(session).Should(Say(`cf unshare-route DOMAIN \[--hostname HOSTNAME\] \[--path PATH\] -s OTHER_SPACE \[-o OTHER_ORG\]`)) + Eventually(session).Should(Say(`\n`)) + + Eventually(session).Should(Say(`EXAMPLES:`)) + Eventually(session).Should(Say(`cf unshare-route example.com --hostname myHost --path foo -s TargetSpace -o TargetOrg # myhost.example.com/foo`)) + Eventually(session).Should(Say(`cf unshare-route example.com --hostname myHost -s TargetSpace # myhost.example.com`)) + Eventually(session).Should(Say(`cf unshare-route example.com --hostname myHost -s TargetSpace -o TargetOrg # myhost.example.com`)) + Eventually(session).Should(Say(`\n`)) + + Eventually(session).Should(Say(`OPTIONS:`)) + Eventually(session).Should(Say(`--hostname, -n\s+Hostname for the HTTP route \(required for shared domains\)`)) + Eventually(session).Should(Say(`--path\s+Path for the HTTP route`)) + Eventually(session).Should(Say(`-o\s+The org of the destination space \(Default: targeted org\)`)) + Eventually(session).Should(Say(`-s\s+The space to be unshared \(Default: targeted space\)`)) + Eventually(session).Should(Say(`\n`)) + + Eventually(session).Should(Say(`SEE ALSO:`)) + Eventually(session).Should(Say(`share-route, delete-route, map-route, routes, unmap-route`)) + + Eventually(session).Should(Exit(0)) + }) + }) + + When("the environment is not setup correctly", func() { + It("fails with the appropriate errors", func() { + helpers.CheckEnvironmentTargetedCorrectly(true, false, ReadOnlyOrg, "unshare-route", "some-domain", "-s SOME_SPACE") + }) + }) + + When("the environment is set up correctly", func() { + var ( + userName string + orgName string + spaceName string + ) + + BeforeEach(func() { + helpers.SkipIfVersionLessThan(ccversion.MinVersionHTTP2RoutingV3) + orgName = helpers.NewOrgName() + spaceName = helpers.NewSpaceName() + + helpers.SetupCF(orgName, spaceName) + userName, _ = helpers.GetCredentials() + }) + + AfterEach(func() { + helpers.QuickDeleteOrg(orgName) + }) + + When("the domain extists", func() { + var ( + domainName string + targetSpaceName string + ) + + BeforeEach(func() { + domainName = helpers.NewDomainName() + }) + + When("the route exists", func() { + var ( + domain helpers.Domain + hostname string + ) + When("the target space is shared in the targedted space", func() { + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "panera-bread" + targetSpaceName = helpers.NewSpaceName() + helpers.CreateSpace(targetSpaceName) + domain.Create() + Eventually(helpers.CF("create-route", domain.Name, "--hostname", hostname)).Should(Exit(0)) + Eventually(helpers.CF("share-route", domain.Name, "--hostname", hostname, "-s", targetSpaceName)).Should(Exit(0)) + }) + + AfterEach(func() { + domain.Delete() + }) + + It("unshares the route to the destination space", func() { + session := helpers.CF("unshare-route", domainName, "--hostname", hostname, "-s", targetSpaceName) + Eventually(session).Should(Say(`Unsharing route %s.%s from space %s as %s`, hostname, domainName, targetSpaceName, userName)) + Eventually(session).Should(Say(`OK`)) + Eventually(session).Should(Exit(0)) + }) + }) + + When("the target organization does not exist", func() { + var targetOrgName string + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "panera-bread" + targetSpaceName = helpers.NewSpaceName() + targetOrgName = helpers.NewOrgName() + domain.Create() + Eventually(helpers.CF("create-route", domain.Name, "--hostname", hostname)).Should(Exit(0)) + }) + + It("exists with 1 and an error message", func() { + session := helpers.CF("unshare-route", domainName, "--hostname", hostname, "-o", targetOrgName, "-s", targetSpaceName) + Eventually(session).Should(Say("Can not unshare route:")) + Eventually(session).Should(Say(`FAILED`)) + Eventually(session).Should(Exit(1)) + }) + }) + + When("the target space exists in another existing org", func() { + var targetOrgName string + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "menchies-icecream" + targetOrgName = helpers.NewOrgName() + targetSpaceName = helpers.NewSpaceName() + helpers.CreateOrgAndSpace(targetOrgName, targetSpaceName) + helpers.SetupCF(orgName, spaceName) + domain.Create() + Eventually(helpers.CF("create-route", domain.Name, "--hostname", hostname)).Should(Exit(0)) + }) + + AfterEach(func() { + domain.Delete() + }) + + It("unshared the route from the intended space", func() { + session := helpers.CF("unshare-route", domainName, "--hostname", hostname, "-o", targetOrgName, "-s", targetSpaceName) + Eventually(session).Should(Say(`Unsharing route %s.%s from space %s as %s`, hostname, domainName, targetSpaceName, userName)) + Eventually(session).Should(Say(`OK`)) + Eventually(session).Should(Exit(0)) + }) + }) + + When("the space does not exist", func() { + var destinationSpaceName string + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "menchies-icecream" + destinationSpaceName = "doesNotExistSpace" + domain.Create() + Eventually(helpers.CF("create-route", domain.Name, "--hostname", hostname)).Should(Exit(0)) + }) + + It("exists with 1 with an error", func() { + session := helpers.CF("unshare-route", domainName, "--hostname", hostname, "-s", destinationSpaceName) + Eventually(session).Should(Say("Can not unshare route:")) + Eventually(session).Should(Say(`FAILED`)) + Eventually(session).Should(Exit(1)) + }) + }) + }) + + When("the route does not exist", func() { + var ( + domain helpers.Domain + hostname string + ) + + When("the target space exists", func() { + BeforeEach(func() { + domain = helpers.NewDomain(orgName, domainName) + hostname = "panera-bread" + targetSpaceName = helpers.NewSpaceName() + helpers.CreateSpace(targetSpaceName) + domain.Create() + }) + + It("exits with 1 with an error message", func() { + session := helpers.CF("unshare-route", domainName, "--hostname", hostname, "-s", targetSpaceName) + Eventually(session).Should(Say("Can not unshare route:")) + Eventually(session).Should(Say(`FAILED`)) + Eventually(session).Should(Exit(1)) + }) + }) + }) + }) + }) +}) From ffa55e895639746bd794bf5df75b85a980656fe1 Mon Sep 17 00:00:00 2001 From: Simon Tremblay Date: Mon, 21 Nov 2022 06:31:16 -0500 Subject: [PATCH 049/248] [gh-2333] Fix all high/critical CVEs for cf CLI v8 --- cf/ssh/ssh.go | 2 +- cf/ssh/ssh_test.go | 2 +- cf/ssh/terminal/helper.go | 2 +- .../terminalfakes/fake_terminal_helper.go | 2 +- go.mod | 16 +++++----- go.sum | 30 +++++++++---------- .../clisshfakes/fake_terminal_helper.go | 2 +- util/clissh/ssh.go | 2 +- util/clissh/ssh_test.go | 2 +- util/clissh/terminal_helper.go | 2 +- 10 files changed, 30 insertions(+), 32 deletions(-) diff --git a/cf/ssh/ssh.go b/cf/ssh/ssh.go index b1bf62f12b0..68fbd5bf50b 100644 --- a/cf/ssh/ssh.go +++ b/cf/ssh/ssh.go @@ -23,7 +23,7 @@ import ( "code.cloudfoundry.org/cli/cf/ssh/options" "code.cloudfoundry.org/cli/cf/ssh/sigwinch" "code.cloudfoundry.org/cli/cf/ssh/terminal" - "github.com/moby/moby/pkg/term" + "github.com/moby/term" ) const ( diff --git a/cf/ssh/ssh_test.go b/cf/ssh/ssh_test.go index 8680011eaef..521e76cea89 100644 --- a/cf/ssh/ssh_test.go +++ b/cf/ssh/ssh_test.go @@ -30,7 +30,7 @@ import ( "code.cloudfoundry.org/diego-ssh/test_helpers/fake_ssh" "code.cloudfoundry.org/lager/lagertest" "github.com/kr/pty" - "github.com/moby/moby/pkg/term" + "github.com/moby/term" "golang.org/x/crypto/ssh" . "github.com/onsi/ginkgo" diff --git a/cf/ssh/terminal/helper.go b/cf/ssh/terminal/helper.go index b755b3ea988..b4d52a84421 100644 --- a/cf/ssh/terminal/helper.go +++ b/cf/ssh/terminal/helper.go @@ -3,7 +3,7 @@ package terminal import ( "io" - "github.com/moby/moby/pkg/term" + "github.com/moby/term" ) //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . TerminalHelper diff --git a/cf/ssh/terminal/terminalfakes/fake_terminal_helper.go b/cf/ssh/terminal/terminalfakes/fake_terminal_helper.go index 8a7ed1a2e2e..82bb9d228bc 100644 --- a/cf/ssh/terminal/terminalfakes/fake_terminal_helper.go +++ b/cf/ssh/terminal/terminalfakes/fake_terminal_helper.go @@ -6,7 +6,7 @@ import ( "sync" "code.cloudfoundry.org/cli/cf/ssh/terminal" - "github.com/moby/moby/pkg/term" + "github.com/moby/term" ) type FakeTerminalHelper struct { diff --git a/go.mod b/go.mod index 5169eb5ea3c..818297feb97 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/mattn/go-colorable v0.1.0 github.com/mattn/go-runewidth v0.0.5-0.20181218000649-703b5e6b11ae github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2 - github.com/moby/moby v1.4.2-0.20171120205147-9de84a78d76e + github.com/moby/term v0.0.0-20221120202655-abb19827d345 github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d github.com/onsi/ginkgo v1.16.4 github.com/onsi/gomega v1.13.0 @@ -40,8 +40,8 @@ require ( github.com/tedsuo/rata v1.0.1-0.20170830210128-07d200713958 github.com/vito/go-interact v0.0.0-20171111012221-fa338ed9e9ec golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e - golang.org/x/net v0.0.0-20220531201128-c960675eff93 - golang.org/x/text v0.3.7 + golang.org/x/net v0.0.0-20220906165146-f3363e06e74c + golang.org/x/text v0.3.8 gopkg.in/cheggaaa/pb.v1 v1.0.28 gopkg.in/yaml.v2 v2.4.0 k8s.io/apimachinery v0.22.2 @@ -50,7 +50,7 @@ require ( require ( cloud.google.com/go v0.65.0 // indirect - github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.18 // indirect github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect @@ -63,7 +63,6 @@ require ( github.com/cloudfoundry/bosh-utils v0.0.0-20180315210917-c6a922e299b8 // indirect github.com/cppforlife/go-patch v0.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/docker/docker v1.4.2-0.20171120205147-9de84a78d76e // indirect github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/go-logr/logr v0.4.0 // indirect @@ -82,13 +81,12 @@ require ( github.com/opencontainers/go-digest v1.0.0-rc1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/tedsuo/ifrit v0.0.0-20191009134036-9a97d0632f00 // indirect - golang.org/x/mod v0.4.2 // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect - golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect + golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect - golang.org/x/tools v0.1.6-0.20210908190839-cf92b39a962c // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + golang.org/x/tools v0.1.12 // indirect google.golang.org/appengine v1.6.6 // indirect google.golang.org/genproto v0.0.0-20211013025323-ce878158c4d4 // indirect google.golang.org/grpc v1.41.0 // indirect diff --git a/go.sum b/go.sum index dc1993b5db4..7a33749f559 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ code.cloudfoundry.org/tlsconfig v0.0.0-20210615191307-5d92ef3894a7/go.mod h1:CKI code.cloudfoundry.org/ykk v0.0.0-20170424192843-e4df4ce2fd4d h1:M+zXqtXJqcsmpL76aU0tdl1ho23eYa4axYoM4gD62UA= code.cloudfoundry.org/ykk v0.0.0-20170424192843-e4df4ce2fd4d/go.mod h1:YUJiVOr5xl0N/RjMxM1tHmgSpBbi5UM+KoVR5AoejO0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.11.18 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM= @@ -122,6 +122,7 @@ github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2 github.com/cppforlife/go-patch v0.1.0 h1:I0fT+gFTSW4xWwvaTaUUVjr9xxjNXJ4naGc01BeQjwY= github.com/cppforlife/go-patch v0.1.0/go.mod h1:67a7aIi94FHDZdoeGSJRRFDp66l9MhaAG1yGxpUoFD8= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/cyphar/filepath-securejoin v0.2.1 h1:5DPkzz/0MwUpvR4fxASKzgApeq2OMFY5FfYtrX28Coo= github.com/cyphar/filepath-securejoin v0.2.1/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -129,8 +130,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docker/distribution v2.8.0+incompatible h1:l9EaZDICImO1ngI+uTifW+ZYvvz7fKISBAKpg+MbWbY= github.com/docker/distribution v2.8.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v1.4.2-0.20171120205147-9de84a78d76e h1:M+/1NNHE/mg+RUox/04+rZoahJVklPfs6xZFECVnxso= -github.com/docker/docker v1.4.2-0.20171120205147-9de84a78d76e/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/drewolson/testflight v1.0.0/go.mod h1:t9oKuuEohRGLb80SWX+uxJHuhX98B7HnojqtW+Ryq30= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= @@ -289,9 +288,9 @@ github.com/mattn/go-runewidth v0.0.5-0.20181218000649-703b5e6b11ae/go.mod h1:H03 github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2 h1:g+4J5sZg6osfvEfkRZxJ1em0VT95/UOZgi/l7zi1/oE= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/moby/moby v1.4.2-0.20171120205147-9de84a78d76e h1:6+Fs/ljqCOuJ4Ie4VUB/wQ/9oSpk2YvtSR5Clf13puk= -github.com/moby/moby v1.4.2-0.20171120205147-9de84a78d76e/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/term v0.0.0-20221120202655-abb19827d345 h1:J9c53/kxIH+2nTKBEfZYFMlhghtHpIHSXpm5VRGHSnU= +github.com/moby/term v0.0.0-20221120202655-abb19827d345/go.mod h1:15ce4BGCFxt7I5NQKT+HV0yEDxmf6fSysfEDiVo3zFM= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -427,8 +426,9 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180418062111-d41e8174641f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -466,8 +466,8 @@ golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220531201128-c960675eff93 h1:MYimHLfoXEpOhqd/zgoA/uoXzHB86AEky4LAx5ij9xA= -golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220906165146-f3363e06e74c h1:yKufUcDwucU5urd+50/Opbt4AYpqthk7wHpHok8f1lo= +golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= 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= @@ -529,8 +529,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -543,8 +543,8 @@ 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= 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 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/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-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -597,8 +597,8 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.6-0.20210908190839-cf92b39a962c h1:C0nyHiBU2m0cR6hDiUORWqQIt3h37wsp1255QBSSXqY= -golang.org/x/tools v0.1.6-0.20210908190839-cf92b39a962c/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/util/clissh/clisshfakes/fake_terminal_helper.go b/util/clissh/clisshfakes/fake_terminal_helper.go index 941fd8e1d1a..3128914d983 100644 --- a/util/clissh/clisshfakes/fake_terminal_helper.go +++ b/util/clissh/clisshfakes/fake_terminal_helper.go @@ -6,7 +6,7 @@ import ( "sync" "code.cloudfoundry.org/cli/util/clissh" - "github.com/moby/moby/pkg/term" + "github.com/moby/term" ) type FakeTerminalHelper struct { diff --git a/util/clissh/ssh.go b/util/clissh/ssh.go index 43fd4f1ef2a..069022872cc 100644 --- a/util/clissh/ssh.go +++ b/util/clissh/ssh.go @@ -19,7 +19,7 @@ import ( "code.cloudfoundry.org/cli/cf/ssh/sigwinch" "code.cloudfoundry.org/cli/util/clissh/ssherror" - "github.com/moby/moby/pkg/term" + "github.com/moby/term" log "github.com/sirupsen/logrus" "golang.org/x/crypto/ssh" ) diff --git a/util/clissh/ssh_test.go b/util/clissh/ssh_test.go index c2cd5ecbffd..58f4d2d744c 100644 --- a/util/clissh/ssh_test.go +++ b/util/clissh/ssh_test.go @@ -28,7 +28,7 @@ import ( "code.cloudfoundry.org/diego-ssh/test_helpers/fake_ssh" "code.cloudfoundry.org/lager/lagertest" "github.com/kr/pty" - "github.com/moby/moby/pkg/term" + "github.com/moby/term" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "golang.org/x/crypto/ssh" diff --git a/util/clissh/terminal_helper.go b/util/clissh/terminal_helper.go index 092fe4915c8..88f72474144 100644 --- a/util/clissh/terminal_helper.go +++ b/util/clissh/terminal_helper.go @@ -3,7 +3,7 @@ package clissh import ( "io" - "github.com/moby/moby/pkg/term" + "github.com/moby/term" ) //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . TerminalHelper From 0cb8539213e0cc5af083b361e00f9565207d718e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Diego=20Gonz=C3=A1lez?= <25335192+jdgonzaleza@users.noreply.github.com> Date: Fri, 2 Dec 2022 11:28:46 -0500 Subject: [PATCH 050/248] Full Integration tests on GHA (#2353) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Updates to the virtual workstation * Adds Integration tests to Github actions: - Integration tests for edge capi linux - Integration tests for min capi - Integration tests for windows - Integration tests for client credential * Updates set-outputs commands Co-authored-by: Juan Diego Gonzalez Co-authored-by: Al Berez Co-authored-by: Cristhian Peña --- .actrc | 1 + .devcontainer/cli.code-workspace | 24 ++ .../win/integrations/integration-tests.ps1 | 102 ++++++ .github/workflows/cf-env-setup.yml | 209 ++++++++++++ .github/workflows/cf-env-unclaim.yml | 36 +++ .github/workflows/integration.yml | 304 ++++++++++++++++++ .github/workflows/run-integration-tests.yml | 92 ++++++ .../workflows/windows-integration-setup.yml | 72 +++++ .gitpod.yml | 34 ++ build_data.yml | 2 + .../commonisolated/common_isolated_setup.go | 4 + 11 files changed, 880 insertions(+) create mode 100644 .actrc create mode 100644 .devcontainer/cli.code-workspace create mode 100644 .github/win/integrations/integration-tests.ps1 create mode 100644 .github/workflows/cf-env-setup.yml create mode 100644 .github/workflows/cf-env-unclaim.yml create mode 100644 .github/workflows/integration.yml create mode 100644 .github/workflows/run-integration-tests.yml create mode 100644 .github/workflows/windows-integration-setup.yml create mode 100644 .gitpod.yml create mode 100644 build_data.yml diff --git a/.actrc b/.actrc new file mode 100644 index 00000000000..b16e42ec2b3 --- /dev/null +++ b/.actrc @@ -0,0 +1 @@ +--artifact-server-path /tmp/artifacts \ No newline at end of file diff --git a/.devcontainer/cli.code-workspace b/.devcontainer/cli.code-workspace new file mode 100644 index 00000000000..9188cd1f7a6 --- /dev/null +++ b/.devcontainer/cli.code-workspace @@ -0,0 +1,24 @@ +{ + "folders": [ + { "path": ".." }, + { "path": "../../cli-ci" }, + { "path": "../../cli-private" }, + { "path": "../../cli-workstation" } + + ], + "settings": { + "github-actions.workflows.pinned.workflows": [ + "cli/.github/workflows/integration.yml" + ] + }, + "extensions": { + "recommendations": [ + "gitpod.gitpod-remote-ssh", + "ms-vsliveshare.vsliveshare", + "redhat.vscode-yaml", + "golang.go", + "vscodevim.vim", + "ms-vscode.makefile-tools" + ] + } +} \ No newline at end of file diff --git a/.github/win/integrations/integration-tests.ps1 b/.github/win/integrations/integration-tests.ps1 new file mode 100644 index 00000000000..f1f2e4d28dd --- /dev/null +++ b/.github/win/integrations/integration-tests.ps1 @@ -0,0 +1,102 @@ +$ErrorActionPreference = "Stop" +trap { $host.SetShouldExit(1) } + +echo "Work Directory: $pwd" +$Env:ROOT="$pwd" + +$null = New-Item -ItemType Directory -Force -Path $Env:TEMP + +# TODO: consider migrating choco to winget https://github.com/microsoft/winget-cli as preferred MS solution +if ((Get-Command "choco" -ErrorAction SilentlyContinue) -eq $null) { + Set-ExecutionPolicy Bypass -Scope Process -Force + [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 + $tempvar = (New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1') + iex ($tempvar) +} + +function Refresh-Choco-Env { + Import-Module "C:\ProgramData\chocolatey\helpers\chocolateyProfile.psm1" + refreshenv + cd $Env:ROOT +} + +Refresh-Choco-Env + +$Env:GOPATH="$Env:ROOT\go" + +$Env:PATH="$Env:HOME\go\bin;" + "$Env:PATH" +$Env:PATH="$Env:GOPATH\bin;" + "$Env:PATH" +$Env:PATH="$Env:GOROOT\bin;" + "$Env:PATH" +$Env:PATH="$pwd;" + "$Env:PATH" +$Env:PATH="$pwd\cli\out;" + "$Env:PATH" + +# This is for DEBUG +# function Get-Env-Info { +# echo "Powershell: $((Get-Host).Version)" +# echo "Working Directory: $pwd" +# echo "GOPATH: $Env:GOPATH" +# echo "PATH:" +# $Env:PATH.split(";") + +# echo "-------------" + +# Get-ChildItem Env: | Format-Table -Wrap -AutoSize +# } + +# Get-Env-Info + +$Env:RUN_ID=(openssl rand -hex 16) +$Env:GOFLAGS = "-mod=mod" + +if ((Get-Command "ginkgo" -ErrorAction SilentlyContinue) -eq $null) { + go install -v github.com/onsi/ginkgo/ginkgo@v1.16.4 +} + +$CF_INT_NAME=(Get-Content $pwd\metadata.json -Raw| Out-String | ConvertFrom-Json).name.trim() +$Env:CF_INT_PASSWORD=(Get-Content $pwd\cf-password -Raw).trim() +$Env:CF_INT_OIDC_PASSWORD=(Get-Content $pwd\uaa-oidc-password -Raw).trim() +$Env:CF_INT_OIDC_USERNAME="admin-oidc" +$Env:CF_INT_API="https://api.$CF_INT_NAME.cf-app.com" +$Env:CF_DIAL_TIMEOUT=15 +# Enable SSL vaildation once toolsmiths supports it +# $Env:SKIP_SSL_VALIDATION="false" + +Import-Certificate -Filepath "$pwd\$CF_INT_NAME.router.ca" -CertStoreLocation "cert:\LocalMachine\root" + +New-Item "go/src/code.cloudfoundry.org" -Type Directory +New-Item -ItemType SymbolicLink -Path "$pwd/go/src/code.cloudfoundry.org/cli" -Target "$pwd/cli" + +cd go/src/code.cloudfoundry.org/cli + +go install github.com/akavel/rsrc@v0.10.2 + +make out/cf-cli_winx64.exe +Move-Item -Path ./out/cf-cli_winx64.exe -Destination ./out/cf.exe -Force + +ginkgo.exe -r ` + -nodes=16 ` + -flakeAttempts=2 ` + -slowSpecThreshold=60 ` + -randomizeAllSpecs ` + ./integration/shared/isolated ` + ./integration/v7/isolated ` + ./integration/shared/experimental ` + ./integration/v7/experimental ` + ./integration/v7/push + +if ($LASTEXITCODE -gt 0) +{ + exit 1 +} + +ginkgo.exe -r ` + -flakeAttempts=2 ` + -slowSpecThreshold=60 ` + -randomizeAllSpecs ` + ./integration/shared/global ` + ./integration/v7/global + +if ($LASTEXITCODE -gt 0) +{ + exit 1 +} \ No newline at end of file diff --git a/.github/workflows/cf-env-setup.yml b/.github/workflows/cf-env-setup.yml new file mode 100644 index 00000000000..9308a80f708 --- /dev/null +++ b/.github/workflows/cf-env-setup.yml @@ -0,0 +1,209 @@ +name: Setup CF Environment + +on: + workflow_call: + inputs: + environment: + required: true + type: string + capi-version: + required: true + type: string + outputs: + environment-name: + description: "Name of claimed environment" + value: ${{ jobs.cf-env-setup.outputs.environment-name }} + +jobs: + cf-env-setup: + name: Setting Up CF env + runs-on: ubuntu-latest + environment: ${{ inputs.environment }} + outputs: + environment-name: ${{ steps.claim-toolsmiths-env.outputs.environment-name }} + steps: + - id: claim-toolsmiths-env + name: Claim Toolsmiths Environment + env: + api_token: ${{ secrets.TOOLSMITHS_API_TOKEN }} + hostname: ${{ secrets.TOOLSMITHS_HOSTNAME }} + notes: CF CLI Github Actions Integration Tests + pool_name: cf-deployment + run: | + while true; do + curl -s --show-error -D >(tee headers.txt >&2) -H 'Accept: application/json' \ + -X POST "https://${hostname}/pooled_gcp_engineering_environments/claim" \ + --data-urlencode "api_token=${api_token}" \ + --data-urlencode "pool_name=${pool_name}" \ + --data-urlencode "notes=${notes}" > metadata.json \ + || echo "Unable to reach server, trying again in 30 seconds..." + + ERR_500="Sorry, the Toolsmiths Environments app is currently encountering issues. Trying again in 30 seconds..." + ERR_429="Sorry, Toolsmiths are out of environments in your requested pool. New environments are on their way but you can stop by the Toolsmiths slack channel for more help." + ERR_409="Sorry, was not able to claim an environment. Trying again in 30 seconds..." + + grep -q -E "HTTP/[[:digit:]\.]{1,3} 401" headers.txt && exit 1 + grep -q -E "HTTP/[[:digit:]\.]{1,3} 404" headers.txt && exit 2 + grep -q -E "HTTP/[[:digit:]\.]{1,3} 500" headers.txt && echo "$ERR_500" + grep -q -E "HTTP/[[:digit:]\.]{1,3} 200" headers.txt && break + grep -q -E "HTTP/[[:digit:]\.]{1,3} 429" && echo "$ERR_429" + grep -q -E "HTTP/[[:digit:]\.]{1,3} 409" && echo "$ERR_409" + + sleep 30 + done + + ENV=$(cat metadata.json | jq -r '.name') + echo "environment-name=${ENV}" >> $GITHUB_OUTPUT + + - name: 'Upload Metadata' + uses: actions/upload-artifact@v3 + with: + name: ${{ steps.claim-toolsmiths-env.outputs.environment-name }} + path: metadata.json + + - name: Checkout cli-ci + uses: actions/checkout@v3 + with: + repository: cloudfoundry/cli-ci + path: cli-ci + + - name: Checkout cf-deployment Min CAPI + if: ${{ inputs.capi-version != 'edge' }} + uses: actions/checkout@v3 + with: + repository: cloudfoundry/cf-deployment + path: cf-deployment + ref: ${{ inputs.capi-version }} + + - name: Checkout cf-deployment + uses: actions/checkout@v3 + if: ${{ inputs.capi-version == 'edge' }} + with: + repository: cloudfoundry/cf-deployment + path: cf-deployment + + - name: Checkout CF deployment tasks + uses: actions/checkout@v3 + with: + repository: cloudfoundry/cf-deployment-concourse-tasks + path: cf-deployment-concourse-tasks + + - name: Checkout cli + uses: actions/checkout@v3 + with: + repository: cloudfoundry/cli + path: cli + ref: linux-min-capi-int-test + + - name: Install Tools + run: | + wget https://github.com/cloudfoundry/bosh-bootloader/releases/download/v8.4.110/bbl-v8.4.110_linux_x86-64 -P /tmp + mv /tmp/bbl-* /usr/local/bin/bbl + chmod +x /usr/local/bin/bbl + bbl --version + + wget https://s3.amazonaws.com/bosh-cli-artifacts/bosh-cli-7.0.1-linux-amd64 --output-document="/usr/local/bin/bosh" + chmod +x /usr/local/bin/bosh + bosh --version + + - name: Deploy edge CAPI with Isolation Segment and OIDC Provider + if: ${{ inputs.capi-version == 'edge' }} + env: + CF_INT_CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} + run: | + # find latest capi + FILENAME="$(aws s3 ls capi-releases --no-sign-request --recursive --region us-east-1 | sort | tail -n 1 | awk '{print $4}')" + aws s3 cp s3://capi-releases/$FILENAME $FILENAME --no-sign-request --region us-east-1 + eval "$(bbl print-env --metadata-file metadata.json)" + bosh upload-release --sha2 "$FILENAME" + rm $FILENAME + + # deploy + bosh -d cf manifest > /tmp/manifest.yml + bosh interpolate /tmp/manifest.yml \ + -o cf-deployment/operations/test/add-persistent-isolation-segment-diego-cell.yml \ + -o cli-ci/ci/infrastructure/operations/add-oidc-provider.yml \ + -o cli-ci/ci/infrastructure/operations/add-uaa-client-credentials.yml \ + -o cli-ci/ci/infrastructure/operations/use-latest-capi.yml \ + -v client-secret="${CF_INT_CLIENT_SECRET}" \ + > ./director.yml + + bosh -d cf deploy director.yml -n + echo "Deployed CAPI version:" + bosh -d cf releases | grep capi + + - name: Deploy MIN CAPI with Isolation Segment and OIDC Provider + if: ${{ inputs.capi-version != 'edge' }} + run: | + # Creates vars files + mkdir vars-files + echo "cs = ${{ secrets.CLIENT_SECRET }}" + cat << EOF > vars-files/vars.yml + client-secret: ${{ secrets.CLIENT_SECRET }} + EOF + + # Copy Ops files + mkdir ops-files + cp cf-deployment/operations/scale-to-one-az.yml ops-files/ + cp cf-deployment/operations/test/add-persistent-isolation-segment-diego-cell.yml ops-files/ + cp cf-deployment/operations/use-compiled-releases.yml ops-files/ + cp cf-deployment/operations/use-internal-lookup-for-route-services.yml ops-files/ + cp cli-ci/ci/infrastructure/operations/add-dummy-windows-stack.yml ops-files/ + cp cli-ci/ci/infrastructure/operations/add-oidc-provider.yml ops-files/ + cp cli-ci/ci/infrastructure/operations/add-uaa-client-credentials.yml ops-files/ + cp cli-ci/ci/infrastructure/operations/add-uaa-client-cf-custom.yml ops-files/ + cp cli-ci/ci/infrastructure/operations/adjust-user-retry-attempts.yml ops-files/ + cp cli-ci/ci/infrastructure/operations/cli-isolation-cell-overrides.yml ops-files/ + cp cli-ci/ci/infrastructure/operations/default-app-memory.yml ops-files/ + cp cli-ci/ci/infrastructure/operations/diego-cell-instances.yml ops-files/ + cp cli-ci/ci/infrastructure/operations/doppler-instances.yml ops-files/ + cp cli-ci/ci/infrastructure/operations/enable-v3-deployments-endpoint.yml ops-files/ + cp cli-ci/ci/infrastructure/operations/give-cf-admin-clients-read-scope.yml ops-files/ + cp cli-ci/ci/infrastructure/operations/reduce-async-service-polling.yml ops-files/ + cp cli-ci/ci/infrastructure/operations/skip-ssl-override.yml ops-files/ + cp cli-ci/ci/infrastructure/operations/uaa-vm_type-override.yml ops-files/ + # Deletes CF-D + eval "$(bbl print-env --metadata-file metadata.json)" + bosh -d cf delete-deployment -n + + # Deploy CF-D + mkdir toolsmiths-env + cp metadata.json toolsmiths-env/metadata + cat metadata.json | jq -r .name > toolsmiths-env/name + export VARS_FILES="vars.yml" + export MANIFEST_FILE="cf-deployment.yml" + export SYSTEM_DOMAIN="" + export REGENERATE_CREDENTIALS=false + export DEPLOY_WITH_UPTIME_MEASUREMENTS=false + export MEASURE_SYSLOG_AVAILABILITY=false + export TCP_DOMAIN="" + export AVAILABLE_PORT="" + export FAIL_ON_DOWNTIME=false + export APP_PUSHABILITY_THRESHOLD=0 + export HTTP_AVAILABILITY_THRESHOLD=0 + export RECENT_LOGS_THRESHOLD=0 + export STREAMING_LOGS_THRESHOLD=0 + export APP_SYSLOG_AVAILABILITY_THRESHOLD=0 + export USE_SINGLE_APP_INSTANCE=false + export BOSH_DEPLOY_ARGS="" + export BOSH_LITE=false + export BBL_JSON_CONFIG="" + export OPS_FILES="add-persistent-isolation-segment-diego-cell.yml \ + use-compiled-releases.yml \ + cli-isolation-cell-overrides.yml \ + default-app-memory.yml \ + skip-ssl-override.yml \ + scale-to-one-az.yml \ + diego-cell-instances.yml \ + doppler-instances.yml \ + uaa-vm_type-override.yml \ + add-uaa-client-credentials.yml \ + add-dummy-windows-stack.yml \ + reduce-async-service-polling.yml \ + add-oidc-provider.yml \ + adjust-user-retry-attempts.yml \ + enable-v3-deployments-endpoint.yml \ + give-cf-admin-clients-read-scope.yml \ + add-uaa-client-cf-custom.yml \ + use-internal-lookup-for-route-services.yml" + ./cf-deployment-concourse-tasks/bosh-deploy/task diff --git a/.github/workflows/cf-env-unclaim.yml b/.github/workflows/cf-env-unclaim.yml new file mode 100644 index 00000000000..21a4ec15ba9 --- /dev/null +++ b/.github/workflows/cf-env-unclaim.yml @@ -0,0 +1,36 @@ +name: Unclaim an environment + +on: + workflow_call: + inputs: + environment: + required: true + type: string + toolsmith-env-name: + required: true + type: string + +jobs: + cf-env-unclaim: + runs-on: ubuntu-latest + environment: ${{ inputs.environment }} + + steps: + - name: Unclaim environment + env: + api_token: ${{ secrets.TOOLSMITHS_API_TOKEN }} + hostname: ${{ secrets.TOOLSMITHS_HOSTNAME }} + run: | + while true; do + output=$(curl -s --show-error -D >(tee headers.txt >&2) -H 'Accept: application/json' \ + -X POST "https://${hostname}/pooled_gcp_engineering_environments/unclaim" \ + --data-urlencode "api_token=${api_token}" \ + --data-urlencode "name=${{ inputs.toolsmith-env-name }}") + + ERR_500="Sorry, the Toolsmiths Environments app is currently encountering issues. Trying again in 30 seconds..." + + grep -q -E "HTTP/[[:digit:]\.]{1,3} 500" headers.txt && echo "$ERR_500" && sleep 30 && continue + grep -q -E "HTTP/[[:digit:]\.]{1,3} 401" headers.txt && echo $(echo "$output" | jq '.messages | join(", ")') && exit 1 + grep -q -E "HTTP/[[:digit:]\.]{1,3} 404" headers.txt && echo $(echo "$output" | jq '.messages | join(", ")') && exit 2 + grep -q -E "HTTP/[[:digit:]\.]{1,3} 202" headers.txt && break + done \ No newline at end of file diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml new file mode 100644 index 00000000000..ce1a4e9841a --- /dev/null +++ b/.github/workflows/integration.yml @@ -0,0 +1,304 @@ +name: Integration Tests + +on: + workflow_dispatch: + pull_request: + branches: + - main + - v8 + - v7 + paths-ignore: + - 'doc/**' + - '.gitpod.yml' + - 'README.md' + push: + branches: + - main + - v8 + - v7 + paths-ignore: + - 'doc/**' + - '.github/**' + - '.gitpod.yml' + - 'README.md' + +permissions: + contents: read + +jobs: + shared-values: + name: Shared Values + runs-on: ubuntu-latest + outputs: + secrets-environment: ${{ steps.set-secrets-environment.outputs.secrets-environment }} + go-version: ${{ steps.set-go-version.outputs.go-version }} + min-capi: ${{ steps.get-min-capi.outputs.min-capi }} + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - id: set-secrets-environment + name: Set environment + run: echo "secrets-environment=PROD" >> $GITHUB_OUTPUT + + - id: set-go-version + name: Parse Golang Version + run: | + go_version=($(grep -E '^go 1\.[[:digit:]]{1,2}' go.mod)) + echo "golang version: ${go_version[1]}" + echo "go-version=${go_version[1]}" >> $GITHUB_OUTPUT + + - id: get-min-capi + name: Get Minimum CAPI Version + run: | + min_capi=($(yq .cf-d-capi-version-min build_data.yml)) + echo "Minimum CAPI version: ${min_capi}" + echo "min-capi=${min_capi}" >> $GITHUB_OUTPUT + +## START edge CAPI + + get-cf-env-with-edge-capi: + name: Setup CF env with EDGE CAPI + needs: shared-values + uses: ./.github/workflows/cf-env-setup.yml + with: + environment: ${{ needs.shared-values.outputs.secrets-environment }} + capi-version: edge + secrets: inherit + + run-integration-tests-cf-env-with-edge-capi: + name: Integration tests with EDGE CAPI + needs: + - shared-values + - get-cf-env-with-edge-capi + uses: ./.github/workflows/run-integration-tests.yml + with: + go-version: ${{ needs.shared-values.outputs.go-version}} + environment: ${{ needs.shared-values.outputs.secrets-environment }} + environment-name: ${{ needs.get-cf-env-with-edge-capi.outputs.environment-name }} + run-with-client-creds: false + + unclaim-cf-env-with-edge-capi: + name: Unclaim CF env with EDGE CAPI + needs: + - shared-values + - get-cf-env-with-edge-capi + - run-integration-tests-cf-env-with-edge-capi + if: always() + uses: ./.github/workflows/cf-env-unclaim.yml + with: + environment: ${{ needs.shared-values.outputs.secrets-environment }} + toolsmith-env-name: ${{ needs.get-cf-env-with-edge-capi.outputs.environment-name }} + secrets: inherit + +## END edge CAPI + +## Start edge CAPI Client Creds + get-cf-env-with-edge-capi-client-creds: + name: Setup CF env with EDGE CAPI Client Credentials + needs: shared-values + uses: ./.github/workflows/cf-env-setup.yml + with: + environment: ${{ needs.shared-values.outputs.secrets-environment }} + capi-version: edge + secrets: inherit + + run-integration-tests-cf-env-with-edge-capi-client-creds: + name: Integration tests with EDGE CAPI Client Credentials + needs: + - shared-values + - get-cf-env-with-edge-capi-client-creds + uses: ./.github/workflows/run-integration-tests.yml + with: + go-version: ${{ needs.shared-values.outputs.go-version}} + environment: ${{ needs.shared-values.outputs.secrets-environment }} + environment-name: ${{ needs.get-cf-env-with-edge-capi-client-creds.outputs.environment-name }} + run-with-client-creds: true + secrets: inherit + + unclaim-cf-env-with-edge-capi-client-creds: + name: Unclaim CF env with EDGE CAPI + needs: + - shared-values + - get-cf-env-with-edge-capi-client-creds + - run-integration-tests-cf-env-with-edge-capi-client-creds + if: always() + uses: ./.github/workflows/cf-env-unclaim.yml + with: + environment: ${{ needs.shared-values.outputs.secrets-environment }} + toolsmith-env-name: ${{ needs.get-cf-env-with-edge-capi-client-creds.outputs.environment-name }} + secrets: inherit +## END edge CAPI Client Creds + +## START min CAPI + get-cf-env-with-min-capi: + name: Setup CF env with MIN CAPI + needs: shared-values + uses: ./.github/workflows/cf-env-setup.yml + with: + environment: ${{ needs.shared-values.outputs.secrets-environment }} + capi-version: ${{ needs.shared-values.outputs.min-capi}} + secrets: inherit + + run-integration-tests-cf-env-with-min-capi: + name: Integration tests with MIN CAPI + needs: + - shared-values + - get-cf-env-with-min-capi + uses: ./.github/workflows/run-integration-tests.yml + with: + go-version: ${{ needs.shared-values.outputs.go-version}} + environment: ${{ needs.shared-values.outputs.secrets-environment }} + environment-name: ${{ needs.get-cf-env-with-min-capi.outputs.environment-name }} + run-with-client-creds: false + + unclaim-cf-env-with-min-capi: + name: Unclaim CF env with MIN CAPI + needs: + - shared-values + - get-cf-env-with-min-capi + - run-integration-tests-cf-env-with-min-capi + if: always() + uses: ./.github/workflows/cf-env-unclaim.yml + with: + environment: ${{ needs.shared-values.outputs.secrets-environment }} + toolsmith-env-name: ${{ needs.get-cf-env-with-min-capi.outputs.environment-name }} + secrets: inherit + +## END min CAPI + +## START windows + get-windows-cf-env-with-edge-capi: + name: Setup CF env with EDGE CAPI for windows + needs: shared-values + uses: ./.github/workflows/cf-env-setup.yml + with: + environment: ${{ needs.shared-values.outputs.secrets-environment }} + capi-version: edge + secrets: inherit + + setup-windows-integration: + name: Setup Integration Tests Windows + needs: + - shared-values + - get-windows-cf-env-with-edge-capi + uses: ./.github/workflows/windows-integration-setup.yml + with: + environment: ${{ needs.shared-values.outputs.secrets-environment }} + environment-name: ${{ needs.get-windows-cf-env-with-edge-capi.outputs.environment-name }} + + run-windows-integration-tests: + name: Run Integration tests Windows + needs: + - shared-values + - get-windows-cf-env-with-edge-capi + - setup-windows-integration + runs-on: windows-latest + defaults: + run: + shell: pwsh + environment: ${{ needs.shared-values.outputs.secrets-environment }} + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + path: cli + - name: Set Up Go + uses: actions/setup-go@v3 + with: + go-version: ${{ needs.shared-values.outputs.go-version}} + check-latest: true + - name: Download metadata + uses: actions/download-artifact@v3 + with: + name: ${{ needs.get-windows-cf-env-with-edge-capi.outputs.environment-name }} + + - name: Download CF data + uses: actions/download-artifact@v3 + with: + name: cf-windows-data + - name: Run Integration Tests + run: cli/.github/win/integrations/integration-tests.ps1 + + unclaim-cf-windows-env-with-edge-capi: + name: Unclaim CF windows env with edge CAPI + needs: + - shared-values + - get-windows-cf-env-with-edge-capi + - run-windows-integration-tests + if: always() + uses: ./.github/workflows/cf-env-unclaim.yml + with: + environment: ${{ needs.shared-values.outputs.secrets-environment }} + toolsmith-env-name: ${{ needs.get-windows-cf-env-with-edge-capi.outputs.environment-name }} + secrets: inherit + +## START windows client credentials + get-windows-cc-cf-env-with-edge-capi: + name: Setup CF env with EDGE CAPI for windows Client Credentials + needs: shared-values + uses: ./.github/workflows/cf-env-setup.yml + with: + environment: ${{ needs.shared-values.outputs.secrets-environment }} + capi-version: edge + secrets: inherit + + setup-windows-integration-client-credentials: + name: Setup Integration Tests Windows Client Credentials + needs: + - shared-values + - get-windows-cc-cf-env-with-edge-capi + uses: ./.github/workflows/windows-integration-setup.yml + with: + environment: ${{ needs.shared-values.outputs.secrets-environment }} + environment-name: ${{ needs.get-windows-cc-cf-env-with-edge-capi.outputs.environment-name }} + + run-windows-integration-client-credentials-tests: + name: Run Integration tests Windows with Client Credentials + env: + CF_INT_CLIENT_ID: potato-face + CF_INT_CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} + needs: + - shared-values + - get-windows-cc-cf-env-with-edge-capi + - setup-windows-integration-client-credentials + runs-on: windows-latest + defaults: + run: + shell: pwsh + environment: ${{ needs.shared-values.outputs.secrets-environment }} + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + path: cli + - name: Set Up Go + uses: actions/setup-go@v3 + with: + go-version: ${{ needs.shared-values.outputs.go-version}} + check-latest: true + - name: Download metadata + uses: actions/download-artifact@v3 + with: + name: ${{ needs.get-windows-cc-cf-env-with-edge-capi.outputs.environment-name }} + + - name: Download CF data + uses: actions/download-artifact@v3 + with: + name: cf-windows-data + - name: Run Integration Tests + run: cli/.github/win/integrations/integration-tests.ps1 + + unclaim-cf-windows-cc-env-with-edge-capi: + name: Unclaim CF windows with Client Credentials env with edge CAPI + needs: + - shared-values + - get-windows-cc-cf-env-with-edge-capi + - run-windows-integration-client-credentials-tests + if: always() + uses: ./.github/workflows/cf-env-unclaim.yml + with: + environment: ${{ needs.shared-values.outputs.secrets-environment }} + toolsmith-env-name: ${{ needs.get-windows-cc-cf-env-with-edge-capi.outputs.environment-name }} + secrets: inherit diff --git a/.github/workflows/run-integration-tests.yml b/.github/workflows/run-integration-tests.yml new file mode 100644 index 00000000000..8c3aef202a0 --- /dev/null +++ b/.github/workflows/run-integration-tests.yml @@ -0,0 +1,92 @@ +name: Run Integration Tests + +on: + workflow_call: + inputs: + environment: + required: true + type: string + environment-name: + required: true + type: string + go-version: + required: true + type: string + run-with-client-creds: + required: true + type: boolean +jobs: + run-integration-tests: + name: Run Integration Tests + runs-on: ubuntu-latest + environment: ${{ inputs.environment }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set Up Go + uses: actions/setup-go@v3 + with: + go-version: ${{ inputs.go-version }} + check-latest: true + - name: Download metadata + uses: actions/download-artifact@v3 + with: + name: ${{ inputs.environment-name }} + - name: Install Tools + run: | + wget https://github.com/cloudfoundry/bosh-bootloader/releases/download/v8.4.110/bbl-v8.4.110_linux_x86-64 -P /tmp + mv /tmp/bbl-* /usr/local/bin/bbl + chmod +x /usr/local/bin/bbl + bbl --version + + wget https://s3.amazonaws.com/bosh-cli-artifacts/bosh-cli-7.0.1-linux-amd64 --output-document="/usr/local/bin/bosh" + chmod +x /usr/local/bin/bosh + bosh --version + + wget https://github.com/cloudfoundry/credhub-cli/releases/download/2.9.4/credhub-linux-2.9.4.tgz -P ~/ + tar xzvf ~/credhub-linux-2.9.4.tgz + mv credhub /usr/local/bin/credhub + chmod +x /usr/local/bin/credhub + credhub --version + rm ~/credhub-linux-2.9.4.tgz + - name: Run Integration Tests + if: ${{ !inputs.run-with-client-creds }} + run: | + ENV=$(cat metadata.json | jq -r '.name') + eval "$(bbl print-env --metadata-file ./metadata.json)" + export CF_INT_PASSWORD="$(credhub get -n /bosh-$ENV/cf/cf_admin_password | bosh interpolate --path /value -)" + export CF_INT_OIDC_USERNAME="admin-oidc" + export CF_INT_OIDC_PASSWORD=$(credhub get -n /bosh-$ENV/cf/uaa_oidc_admin_password | bosh interpolate --path /value -) + export CF_INT_API="https://api.${ENV}.cf-app.com" + export CF_DIAL_TIMEOUT=15 + export CF_USERNAME=admin + export FLAKE_ATTEMPTS=2 + export NODES=16 + go install github.com/onsi/ginkgo/ginkgo@v1.16.4 + + + make build + export PATH="$(pwd)/out:$PATH" + make integration-tests-full-ci + - name: Run Integration Tests with client credentials + if: ${{ inputs.run-with-client-creds }} + env: + CF_INT_CLIENT_ID: 'potato-face' + CF_INT_CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} + run: | + ENV=$(cat metadata.json | jq -r '.name') + eval "$(bbl print-env --metadata-file ./metadata.json)" + export CF_INT_PASSWORD="$(credhub get -n /bosh-$ENV/cf/cf_admin_password | bosh interpolate --path /value -)" + export CF_INT_OIDC_USERNAME="admin-oidc" + export CF_INT_OIDC_PASSWORD=$(credhub get -n /bosh-$ENV/cf/uaa_oidc_admin_password | bosh interpolate --path /value -) + export CF_INT_API="https://api.${ENV}.cf-app.com" + export CF_DIAL_TIMEOUT=15 + export CF_USERNAME=admin + export FLAKE_ATTEMPTS=2 + export NODES=16 + go install github.com/onsi/ginkgo/ginkgo@v1.16.4 + + + make build + export PATH="$(pwd)/out:$PATH" + make integration-tests-full-ci diff --git a/.github/workflows/windows-integration-setup.yml b/.github/workflows/windows-integration-setup.yml new file mode 100644 index 00000000000..44a8a2f2bbe --- /dev/null +++ b/.github/workflows/windows-integration-setup.yml @@ -0,0 +1,72 @@ +name: Setup Integration Tests Windows + +on: + workflow_call: + inputs: + environment: + required: true + type: string + environment-name: + required: true + type: string +jobs: + setup-integration-windows: + name: Setup Integration Tests Windows + runs-on: ubuntu-latest + environment: ${{ inputs.environment }} + steps: + - name: Download metadata + uses: actions/download-artifact@v3 + with: + name: ${{ inputs.environment-name }} + + - name: Checkout + uses: actions/checkout@v3 + with: + path: cli + + - name: Install Tools + run: | + wget https://github.com/cloudfoundry/bosh-bootloader/releases/download/v8.4.110/bbl-v8.4.110_linux_x86-64 -P /tmp + mv /tmp/bbl-* /usr/local/bin/bbl + chmod +x /usr/local/bin/bbl + bbl --version + + wget https://s3.amazonaws.com/bosh-cli-artifacts/bosh-cli-7.0.1-linux-amd64 --output-document="/usr/local/bin/bosh" + chmod +x /usr/local/bin/bosh + bosh --version + + wget https://github.com/cloudfoundry/credhub-cli/releases/download/2.9.4/credhub-linux-2.9.4.tgz -P ~/ + tar xzvf ~/credhub-linux-2.9.4.tgz + mv credhub /usr/local/bin/credhub + chmod +x /usr/local/bin/credhub + credhub --version + rm ~/credhub-linux-2.9.4.tgz + + - name: Setup Integration Tests + id: setup-windows-integration-step + run: | + ENV=$(cat metadata.json | jq -r '.name') + DATA_DIR=$PWD/cf-data + mkdir -p $DATA_DIR + eval "$(bbl print-env --metadata-file metadata.json)" + + credhub login + CF_INT_PASSWORD=$(credhub get -n /bosh-$ENV/cf/cf_admin_password | bosh interpolate --path /value -) + CF_INT_OIDC_PASSWORD=$(credhub get -n /bosh-$ENV/cf/uaa_oidc_admin_password | bosh interpolate --path /value -) + + credhub get --name /bosh-$ENV/cf/router_ca | bosh interpolate - --path /value/certificate > $DATA_DIR/$ENV.router.ca + + echo "Deployed CAPI version:" + bosh -d cf releases | grep capi + + # output password into a temp file for consumption by Windows + echo $CF_INT_PASSWORD > $DATA_DIR/cf-password + echo $CF_INT_OIDC_PASSWORD > $DATA_DIR/uaa-oidc-password + + echo "data=$DATA_DIR" >> $GITHUB_OUTPUT + - name: 'Upload CF Data' + uses: actions/upload-artifact@v3 + with: + name: cf-windows-data + path: ${{ steps.setup-windows-integration-step.outputs.data }} diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 00000000000..614f7d18cc0 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,34 @@ +additionalRepositories: + - url: https://github.com/cloudfoundry/cli-ci + - url: https://github.com/cloudfoundry/cli-private + - url: https://github.com/cloudfoundry/cli-workstation + +workspaceLocation: cli/.devcontainer/cli.code-workspace + +tasks: + - name: Setup Workspace + before: > + sudo apt install --yes + icdiff + tldr + fzf + + brew install + asdf + cloudfoundry/tap/credhub-cli + cloudfoundry/tap/bbl + cloudfoundry/tap/bosh-cli + act + tmux + neovim + init: > + tldr --update + + make clean build + command: out/cf version + +vscode: + extensions: + - vscodevim.vim + - eamodio.gitlens + - golang.go diff --git a/build_data.yml b/build_data.yml new file mode 100644 index 00000000000..d5264336456 --- /dev/null +++ b/build_data.yml @@ -0,0 +1,2 @@ +build-version: 8.4.0 +cf-d-capi-version-min: v16.11.0 diff --git a/integration/helpers/commonisolated/common_isolated_setup.go b/integration/helpers/commonisolated/common_isolated_setup.go index 0960c1acf68..77be9adbe40 100644 --- a/integration/helpers/commonisolated/common_isolated_setup.go +++ b/integration/helpers/commonisolated/common_isolated_setup.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" "code.cloudfoundry.org/cli/integration/helpers" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -41,6 +42,9 @@ func CommonGinkgoSetup( helpers.SetupSynchronizedSuite(func() { helpers.EnableFeatureFlag("diego_docker") helpers.EnableFeatureFlag("service_instance_sharing") + if helpers.IsVersionMet(ccversion.MinVersionHTTP2RoutingV3) { + helpers.EnableFeatureFlag("route_sharing") + } }) _, _ = GinkgoWriter.Write([]byte("==============================End of Global FIRST Node Synchronized Before Each==============================")) From eaa7204aad6776f3a872e121e600c25d0fb5a9af Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Fri, 2 Dec 2022 12:39:06 -0500 Subject: [PATCH 051/248] Spelling (#2340) (#2355) * spelling: aardvark, alerts, aligns, already, application, assert, asynchronously, authentication, because, between, buildpack, buildpacks, canonical, conceptualize, confirming, connection, constructors, containing, controller, correctly, coverage, default, delete, dereferencing, describing, directory, displayed, displays, error, errors, example, executable, exist, existence, exists, explicit, extra, failure, forces, garbage, github, ignored, improperly, incur, information, input, inputted, intensity, interaction, intercept, interpolate, into, invalid, language, languages, laying-out, lifecycle, look, message, mismatch, multiple, nonexistent, nonexistenttld, not, nowhere, occurs, organization, original, output, overridden, packages, parameter, plugins, preexisting, pseudo, receive, repository, request, resource, response, retrieving, rhinoceros, running, security, selector, separate, separator, space, specified, successfully, superfluous, targeting, the, timeout, translatable, unknown, unlimited, unshare, utilities, version Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- .github/workflows/build-sign-upload.yml | 6 +- .../app_not_found_in_manifest_error.go | 2 +- .../actionerror/no_eligible_packages_error.go | 2 +- actor/pluginaction/plugin_repository_test.go | 2 +- actor/pluginaction/uninstall_test.go | 4 +- actor/v7action/application_test.go | 2 +- actor/v7action/buildpack_test.go | 4 +- actor/v7action/domain_test.go | 4 +- actor/v7action/isolation_segment_test.go | 2 +- actor/v7action/package_test.go | 2 +- actor/v7action/security_group_test.go | 20 ++--- actor/v7action/stack_test.go | 2 +- actor/v7action/task.go | 2 +- .../handle_app_path_override_test.go | 4 +- .../handle_default_route_override_test.go | 6 +- .../handle_stack_override_test.go | 2 +- api/cloudcontroller/ccv3/internal/routing.go | 2 +- api/cloudcontroller/connection.go | 2 +- .../wrapper/request_logger_test.go | 4 +- api/plugin/wrapper/request_logger_test.go | 4 +- api/router/wrapper/request_logger_test.go | 4 +- api/uaa/client_test.go | 2 +- api/uaa/errors.go | 4 +- api/uaa/internal/routing.go | 2 +- api/uaa/wrapper/request_logger_test.go | 4 +- .../brokerbuilder/broker_builder_test.go | 2 +- .../plugin_installer_with_repo.go | 4 +- cf/api/appinstances/app_instances_test.go | 4 +- cf/api/featureflags/feature_flags_test.go | 2 +- cf/api/organizations/organizations_test.go | 2 +- cf/appfiles/cf_ignore_test.go | 2 +- cf/commandregistry/dependency_test.go | 2 +- cf/commands/application/apps_test.go | 2 +- cf/commands/application/copy_source_test.go | 2 +- cf/commands/application/push_test.go | 2 +- cf/commands/application/ssh_test.go | 2 +- .../buildpack/delete_buildpack_test.go | 2 +- cf/commands/config_test.go | 2 +- cf/commands/curl_test.go | 2 +- .../domain/delete_shared_domain_test.go | 4 +- cf/commands/login_test.go | 2 +- cf/commands/organization/create_org_test.go | 2 +- cf/commands/plugin/install_plugin_test.go | 2 +- .../pluginrepo/add_plugin_repo_test.go | 2 +- .../pluginrepo/remove_plugin_repo_test.go | 2 +- cf/commands/quota/delete_quota_test.go | 8 +- .../create_security_group_test.go | 2 +- cf/commands/service/create_service_test.go | 4 +- .../create_user_provided_service_test.go | 2 +- cf/commands/service/unbind_service_test.go | 2 +- .../update_user_provided_service_test.go | 2 +- .../disable_service_access_test.go | 2 +- .../enable_service_access_test.go | 2 +- .../spacequota/create_space_quota_test.go | 4 +- .../spacequota/delete_space_quota_test.go | 8 +- cf/commands/user/delete_user_test.go | 2 +- cf/commands/user/org_users_test.go | 6 +- cf/flags/flags_test.go | 6 +- cf/i18n/README-i18n.md | 2 +- cf/ssh/options/ssh_options_test.go | 4 +- cf/ssh/ssh_test.go | 4 +- cf/terminal/table.go | 4 +- cf/util/downloader/file_download_test.go | 2 +- cf/util/testhelpers/io/io.go | 4 +- .../matchers/match_func_name_test.go | 2 +- cf/util/testhelpers/net/server.go | 2 +- command/common/install_plugin_command.go | 2 +- .../install_plugin_from_repo_command_test.go | 2 +- command/v7/add_network_policy_command_test.go | 2 +- command/v7/auth_command.go | 2 +- command/v7/buildpacks_command_test.go | 2 +- .../v7/create_app_manifest_command_test.go | 2 +- command/v7/curl_command.go | 18 ++--- command/v7/curl_command_test.go | 30 +++---- command/v7/delete_command_test.go | 2 +- .../v7/delete_shared_domain_command_test.go | 2 +- .../v7/disable_feature_flag_command_test.go | 2 +- .../v7/enable_feature_flag_command_test.go | 2 +- command/v7/login_command_test.go | 2 +- command/v7/shared/new_clients_test.go | 2 +- command/v7/ssh_command_test.go | 4 +- doc/adr/0004-v7-push-refactor.md | 4 +- doc/adr/0007-integration-vs-command-test.md | 2 +- doc/adr/0012-de-version-v8-code-base.md | 2 +- fixtures/plugins/test_1.go | 2 +- i18n/resources/i18n_resources.go | 16 ++-- integration/helpers/login.go | 14 ++-- integration/helpers/version.go | 14 ++-- .../isolated/internationalization_test.go | 16 ++-- integration/v7/isolated/auth_command_test.go | 6 +- .../v7/isolated/create_private_domain_test.go | 2 +- .../isolated/create_service_command_test.go | 2 +- ...eate_user_provided_service_command_test.go | 4 +- .../v7/isolated/delete_command_test.go | 2 +- .../delete_orphaned_routes_command_test.go | 2 +- .../delete_private_domain_command_test.go | 4 +- .../v7/isolated/delete_space_command_test.go | 2 +- .../v7/isolated/delete_user_command_test.go | 4 +- .../v7/isolated/events_command_test.go | 2 +- .../v7/isolated/labels_command_test.go | 66 ++++++++-------- integration/v7/isolated/login_command_test.go | 4 +- .../isolated/network_policies_command_test.go | 2 +- .../v7/isolated/oauth_token_command_test.go | 4 +- .../v7/isolated/restage_command_test.go | 2 +- .../v7/isolated/revisions_command_test.go | 2 +- .../isolated/service_access_command_test.go | 18 ++--- .../v7/isolated/set_label_command_test.go | 10 +-- .../v7/isolated/share_route_command_test.go | 4 +- .../space_ssh_allowed_command_test.go | 2 +- .../v7/isolated/unset_label_command_test.go | 4 +- ...date_user_provided_service_command_test.go | 4 +- plugin/plugin_examples/basic_plugin.go | 4 +- plugin/plugin_examples/echo.go | 2 +- resources/droplet_resource.go | 2 +- util/clissh/ssh_test.go | 4 +- util/configv3/plugins_config_test.go | 2 +- util/manifest/application.go | 2 +- util/manifestparser/application.go | 2 +- util/manifestparser/application_test.go | 2 +- util/manifestparser/process.go | 2 +- util/randomword/generator.go | 4 +- util/ui/i18n.go | 2 +- util/ui/i18n_test.go | 2 +- util/ui/log_message_test.go | 6 +- util/ui/prompt.go | 10 +-- util/ui/prompt_test.go | 6 +- util/ui/table_test.go | 2 +- util/ui/ui.go | 78 +++++++++---------- util/ui/ui_for_push.go | 4 +- util/ui/ui_for_push_test.go | 30 +++---- util/ui/ui_test.go | 22 +++--- util/ui/ui_v7_test.go | 10 +-- 133 files changed, 356 insertions(+), 356 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a698e6eb211..db63429326d 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -31,7 +31,7 @@ Explain why this functionality should be in the cf CLI, as opposed to a plugin. ## Applicable Issues -List any applicable Github Issues here +List any applicable GitHub Issues here ## How Urgent Is The Change? diff --git a/.github/workflows/build-sign-upload.yml b/.github/workflows/build-sign-upload.yml index d516281b37e..e286b5e36a1 100644 --- a/.github/workflows/build-sign-upload.yml +++ b/.github/workflows/build-sign-upload.yml @@ -134,7 +134,7 @@ jobs: echo "golang version: ${go_version[1]}" echo "::set-output name=go-version::${go_version[1]}" - # This is for debugging. It's equivalent to fly intecept + # This is for debugging. It's equivalent to fly intercept # - name: Setup upterm session # env: # AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} @@ -850,12 +850,12 @@ jobs: mv cf-cli-windows-binaries/cf-cli_winx64.exe winx64/cf${VERSION_MAJOR}.exe pushd win32 prepare_win_artifacts - # -y flag avoids the default behavior of derefencing the link, so we archive the symlink as-is + # -y flag avoids the default behavior of dereferencing the link, so we archive the symlink as-is zip -y cf${VERSION_MAJOR}-cli_${INSTALLER_RELEASE_VERSION}_win32.zip * popd pushd winx64 prepare_win_artifacts - # -y flag avoids the default behavior of derefencing the link, so we archive the symlink as-is + # -y flag avoids the default behavior of dereferencing the link, so we archive the symlink as-is zip -y cf${VERSION_MAJOR}-cli_${INSTALLER_RELEASE_VERSION}_winx64.zip * popd popd diff --git a/actor/actionerror/app_not_found_in_manifest_error.go b/actor/actionerror/app_not_found_in_manifest_error.go index 0c20cb04f73..ddb827e47f8 100644 --- a/actor/actionerror/app_not_found_in_manifest_error.go +++ b/actor/actionerror/app_not_found_in_manifest_error.go @@ -7,5 +7,5 @@ type AppNotFoundInManifestError struct { } func (e AppNotFoundInManifestError) Error() string { - return fmt.Sprintf("specfied app: %s not found in manifest", e.Name) + return fmt.Sprintf("specified app: %s not found in manifest", e.Name) } diff --git a/actor/actionerror/no_eligible_packages_error.go b/actor/actionerror/no_eligible_packages_error.go index 73eee7e318a..c358c4ad200 100644 --- a/actor/actionerror/no_eligible_packages_error.go +++ b/actor/actionerror/no_eligible_packages_error.go @@ -12,7 +12,7 @@ func (e NoEligiblePackagesError) Error() string { case e.AppName != "": return fmt.Sprintf("App '%s' has no eligible packages.", e.AppName) default: - return fmt.Sprintf("No eligible pacakges available for app.") + return fmt.Sprintf("No eligible packages available for app.") } } diff --git a/actor/pluginaction/plugin_repository_test.go b/actor/pluginaction/plugin_repository_test.go index d7d3956aab5..07e86248717 100644 --- a/actor/pluginaction/plugin_repository_test.go +++ b/actor/pluginaction/plugin_repository_test.go @@ -104,7 +104,7 @@ var _ = Describe("Plugin Repository Actions", func() { }) }) - When("the repository name is the same and repostiroy URL is the same except for trailing slash", func() { + When("the repository name is the same and repository URL is the same except for trailing slash", func() { BeforeEach(func() { fakeConfig.PluginRepositoriesReturns([]configv3.PluginRepository{ { diff --git a/actor/pluginaction/uninstall_test.go b/actor/pluginaction/uninstall_test.go index 895f4e2cb54..5320840f80b 100644 --- a/actor/pluginaction/uninstall_test.go +++ b/actor/pluginaction/uninstall_test.go @@ -55,8 +55,8 @@ var _ = Describe("Plugin actor", func() { }) It("returns a PluginNotFoundError", func() { - err := actor.UninstallPlugin(fakePluginUninstaller, "some-non-existent-plugin") - Expect(err).To(MatchError(actionerror.PluginNotFoundError{PluginName: "some-non-existent-plugin"})) + err := actor.UninstallPlugin(fakePluginUninstaller, "some-nonexistent-plugin") + Expect(err).To(MatchError(actionerror.PluginNotFoundError{PluginName: "some-nonexistent-plugin"})) }) }) diff --git a/actor/v7action/application_test.go b/actor/v7action/application_test.go index e360fd5dd74..d1e64b735e5 100644 --- a/actor/v7action/application_test.go +++ b/actor/v7action/application_test.go @@ -286,7 +286,7 @@ var _ = Describe("Application Actions", func() { }) It("returns an ApplicationNotFoundError and the warnings", func() { - _, warnings, err := actor.GetApplicationsByGUIDs([]string{"some-app-guid", "non-existent-app-guid"}) + _, warnings, err := actor.GetApplicationsByGUIDs([]string{"some-app-guid", "nonexistent-app-guid"}) Expect(warnings).To(ConsistOf("some-warning")) Expect(err).To(MatchError(actionerror.ApplicationsNotFoundError{})) }) diff --git a/actor/v7action/buildpack_test.go b/actor/v7action/buildpack_test.go index 22052d53b32..c4d0847497c 100644 --- a/actor/v7action/buildpack_test.go +++ b/actor/v7action/buildpack_test.go @@ -120,7 +120,7 @@ var _ = Describe("Buildpack", func() { nil) }) - It("returns warnings and a BuilpackNotFoundError", func() { + It("returns warnings and a BuildpackNotFoundError", func() { Expect(executeErr).To(MatchError(actionerror.BuildpackNotFoundError{BuildpackName: buildpackName, StackName: buildpackStack})) Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2")) }) @@ -319,7 +319,7 @@ var _ = Describe("Buildpack", func() { Describe("UpdateBuildpackByNameAndStack", func() { var ( - buildpackName = "my-buidpack" + buildpackName = "my-buildpack" buildpackStack = "my-stack" buildpack = resources.Buildpack{ Stack: "new-stack", diff --git a/actor/v7action/domain_test.go b/actor/v7action/domain_test.go index 645ac92fb25..09e4d3760a3 100644 --- a/actor/v7action/domain_test.go +++ b/actor/v7action/domain_test.go @@ -572,7 +572,7 @@ var _ = Describe("Domain Actions", func() { BeforeEach(func() { fakeCloudControllerClient.UnsharePrivateDomainFromOrgReturns( ccv3.Warnings{"unshare-domain-warning"}, - errors.New("unsahre-domain-error"), + errors.New("unshare-domain-error"), ) }) @@ -582,7 +582,7 @@ var _ = Describe("Domain Actions", func() { Expect(actualDomainGUID).To(Equal("private-domain-guid")) Expect(actualOrgGUID).To(Equal("org-guid")) - Expect(executeErr).To(MatchError(errors.New("unsahre-domain-error"))) + Expect(executeErr).To(MatchError(errors.New("unshare-domain-error"))) Expect(warnings).To(ConsistOf("get-orgs-warning", "get-domains-warning", "unshare-domain-warning")) }) }) diff --git a/actor/v7action/isolation_segment_test.go b/actor/v7action/isolation_segment_test.go index 8b8a89e7ef8..9be1a9d897f 100644 --- a/actor/v7action/isolation_segment_test.go +++ b/actor/v7action/isolation_segment_test.go @@ -711,7 +711,7 @@ var _ = Describe("Isolation Segment Actions", func() { }) }) - When("fetching the resourece fails", func() { + When("fetching the resource fails", func() { BeforeEach(func() { fakeCloudControllerClient.GetOrganizationDefaultIsolationSegmentReturns( resources.Relationship{}, diff --git a/actor/v7action/package_test.go b/actor/v7action/package_test.go index 1bcaf162c5c..57727c9e704 100644 --- a/actor/v7action/package_test.go +++ b/actor/v7action/package_test.go @@ -617,7 +617,7 @@ var _ = Describe("Package Actions", func() { Expect(tableWarnings).To(ConsistOf("some-app-warning", "some-package-warning", "upload-package-warning", "poll-package-warning", "poll-package-warning")) - // hacky, get packages is called an extry time cause the + // hacky, get packages is called an extra time cause the // JustBeforeEach executes everything once as well Expect(fakeCloudControllerClient.GetPackageCallCount()).To(Equal(3)) Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(3)) diff --git a/actor/v7action/security_group_test.go b/actor/v7action/security_group_test.go index ed0a72500eb..94229fdec76 100644 --- a/actor/v7action/security_group_test.go +++ b/actor/v7action/security_group_test.go @@ -697,7 +697,7 @@ var _ = Describe("Security Group Actions", func() { ) }) - It("makes mutiple calls to get spaces", func() { + It("makes multiple calls to get spaces", func() { Expect(len(securityGroupSummaries)).To(Equal(1)) Expect(fakeCloudControllerClient.GetSpacesCallCount()).To(Equal(batches)) Expect(fakeCloudControllerClient.GetSpacesArgsForCall(0)). @@ -1038,7 +1038,7 @@ var _ = Describe("Security Group Actions", func() { }) }) - When("the seurity group is not bound to the space", func() { + When("the security group is not bound to the space", func() { BeforeEach(func() { fakeCloudControllerClient.UnbindSecurityGroupStagingSpaceReturns( ccv3.Warnings{"get-security-group-warning"}, @@ -1240,7 +1240,7 @@ var _ = Describe("Security Group Actions", func() { var ( securityGroupName = "tom" globallyEnabled bool - lifeycle constant.SecurityGroupLifecycle + lifecycle constant.SecurityGroupLifecycle executeErr error trueValue = true @@ -1248,7 +1248,7 @@ var _ = Describe("Security Group Actions", func() { ) JustBeforeEach(func() { - warnings, executeErr = actor.UpdateSecurityGroupGloballyEnabled(securityGroupName, lifeycle, globallyEnabled) + warnings, executeErr = actor.UpdateSecurityGroupGloballyEnabled(securityGroupName, lifecycle, globallyEnabled) }) When("the request succeeds", func() { @@ -1273,7 +1273,7 @@ var _ = Describe("Security Group Actions", func() { When("updating staging to true", func() { BeforeEach(func() { - lifeycle = constant.SecurityGroupLifecycleStaging + lifecycle = constant.SecurityGroupLifecycleStaging globallyEnabled = true }) @@ -1298,7 +1298,7 @@ var _ = Describe("Security Group Actions", func() { When("updating staging to false", func() { BeforeEach(func() { - lifeycle = constant.SecurityGroupLifecycleStaging + lifecycle = constant.SecurityGroupLifecycleStaging globallyEnabled = false }) @@ -1323,7 +1323,7 @@ var _ = Describe("Security Group Actions", func() { When("updating running to true", func() { BeforeEach(func() { - lifeycle = constant.SecurityGroupLifecycleRunning + lifecycle = constant.SecurityGroupLifecycleRunning globallyEnabled = true }) @@ -1348,7 +1348,7 @@ var _ = Describe("Security Group Actions", func() { When("updating running to false", func() { BeforeEach(func() { - lifeycle = constant.SecurityGroupLifecycleRunning + lifecycle = constant.SecurityGroupLifecycleRunning globallyEnabled = false }) @@ -1374,7 +1374,7 @@ var _ = Describe("Security Group Actions", func() { When("the request to get the security group errors", func() { BeforeEach(func() { - lifeycle = constant.SecurityGroupLifecycleRunning + lifecycle = constant.SecurityGroupLifecycleRunning globallyEnabled = false fakeCloudControllerClient.GetSecurityGroupsReturns( @@ -1398,7 +1398,7 @@ var _ = Describe("Security Group Actions", func() { When("the request to update the security group errors", func() { BeforeEach(func() { - lifeycle = constant.SecurityGroupLifecycleRunning + lifecycle = constant.SecurityGroupLifecycleRunning globallyEnabled = false fakeCloudControllerClient.GetSecurityGroupsReturns( diff --git a/actor/v7action/stack_test.go b/actor/v7action/stack_test.go index aaab0d4aa00..5dc3bf77e1f 100644 --- a/actor/v7action/stack_test.go +++ b/actor/v7action/stack_test.go @@ -157,7 +157,7 @@ var _ = Describe("Stack", func() { Expect(warnings).To(ConsistOf("some-stack-warning")) Expect(fakeCloudControllerClient.GetStacksCallCount()).To(Equal(1)) }) - When("a label selctor is passed in", func() { + When("a label selector is passed in", func() { BeforeEach(func() { labelSelector = "some-label-selector" }) diff --git a/actor/v7action/task.go b/actor/v7action/task.go index fd255bff205..abebb726ecf 100644 --- a/actor/v7action/task.go +++ b/actor/v7action/task.go @@ -25,7 +25,7 @@ func (actor Actor) RunTask(appGUID string, task resources.Task) (resources.Task, } // GetApplicationTasks returns a list of tasks associated with the provided -// appplication GUID. +// application GUID. func (actor Actor) GetApplicationTasks(appGUID string, sortOrder SortOrder) ([]resources.Task, Warnings, error) { tasks, warnings, err := actor.CloudControllerClient.GetApplicationTasks(appGUID) actorWarnings := Warnings(warnings) diff --git a/actor/v7pushaction/handle_app_path_override_test.go b/actor/v7pushaction/handle_app_path_override_test.go index b77a6d521dd..fba1747aead 100644 --- a/actor/v7pushaction/handle_app_path_override_test.go +++ b/actor/v7pushaction/handle_app_path_override_test.go @@ -143,7 +143,7 @@ var _ = Describe("HandleAppPathOverride", func() { parsedManifest = manifestparser.Manifest{ Applications: []manifestparser.Application{ { - Path: "some-non-existent-path", + Path: "some-nonexistent-path", }, }, } @@ -151,7 +151,7 @@ var _ = Describe("HandleAppPathOverride", func() { It("returns an error", func() { Expect(executeErr).To(MatchError(manifestparser.InvalidManifestApplicationPathError{ - Path: "some-non-existent-path", + Path: "some-nonexistent-path", })) }) }) diff --git a/actor/v7pushaction/handle_default_route_override_test.go b/actor/v7pushaction/handle_default_route_override_test.go index 3fed099f086..a33aed69aa0 100644 --- a/actor/v7pushaction/handle_default_route_override_test.go +++ b/actor/v7pushaction/handle_default_route_override_test.go @@ -9,7 +9,7 @@ import ( . "github.com/onsi/gomega" ) -var _ = Describe("HandleDefualtRouteOverride", func() { +var _ = Describe("HandleDefaultRouteOverride", func() { var ( originalManifest manifestparser.Manifest transformedManifest manifestparser.Manifest @@ -57,8 +57,8 @@ var _ = Describe("HandleDefualtRouteOverride", func() { }) - // CLI doesnt know about the routes field but CAPI ignores defualt route if routes is specified - // so we are ok adding defualt route even with the presence of a routes field + // CLI doesnt know about the routes field but CAPI ignores default route if routes is specified + // so we are ok adding default route even with the presence of a routes field When("the manifest has no routing fields", func() { BeforeEach(func() { diff --git a/actor/v7pushaction/handle_stack_override_test.go b/actor/v7pushaction/handle_stack_override_test.go index 9c6d3e18752..ed79874f66c 100644 --- a/actor/v7pushaction/handle_stack_override_test.go +++ b/actor/v7pushaction/handle_stack_override_test.go @@ -37,7 +37,7 @@ var _ = Describe("HandleStackOverride", func() { } }) - It("will retain the origional stack value", func() { + It("will retain the original stack value", func() { Expect(executeErr).To(Not(HaveOccurred())) Expect(transformedManifest.Applications[0].Stack).To(Equal("og_cflinuxfs")) }) diff --git a/api/cloudcontroller/ccv3/internal/routing.go b/api/cloudcontroller/ccv3/internal/routing.go index 4b818cfca0c..b6589de43ba 100644 --- a/api/cloudcontroller/ccv3/internal/routing.go +++ b/api/cloudcontroller/ccv3/internal/routing.go @@ -12,7 +12,7 @@ import ( // Params map path keys to values. For example, if your route has the path // pattern: // /person/:person_id/pets/:pet_type -// Then a correct Params map would lool like: +// Then a correct Params map would look like: // router.Params{ // "person_id": "123", // "pet_type": "cats", diff --git a/api/cloudcontroller/connection.go b/api/cloudcontroller/connection.go index 65ab2169fdd..8d0ee03b1ae 100644 --- a/api/cloudcontroller/connection.go +++ b/api/cloudcontroller/connection.go @@ -1,4 +1,4 @@ -// Package cloudcontroller contains shared utilies between the V2 and V3 +// Package cloudcontroller contains shared utilities between the V2 and V3 // clients. // // These sets of packages are still under development/pre-pre-pre...alpha. Use diff --git a/api/cloudcontroller/wrapper/request_logger_test.go b/api/cloudcontroller/wrapper/request_logger_test.go index 81e3deb124e..920d72716f2 100644 --- a/api/cloudcontroller/wrapper/request_logger_test.go +++ b/api/cloudcontroller/wrapper/request_logger_test.go @@ -171,7 +171,7 @@ var _ = Describe("Request Logger", func() { }) }) - When("an error occures while trying to log the request", func() { + When("an error occurs while trying to log the request", func() { var expectedErr error BeforeEach(func() { @@ -348,7 +348,7 @@ var _ = Describe("Request Logger", func() { }) }) - When("an error occures while trying to log the response", func() { + When("an error occurs while trying to log the response", func() { var ( originalErr error expectedErr error diff --git a/api/plugin/wrapper/request_logger_test.go b/api/plugin/wrapper/request_logger_test.go index ad447373f64..377723ab538 100644 --- a/api/plugin/wrapper/request_logger_test.go +++ b/api/plugin/wrapper/request_logger_test.go @@ -160,7 +160,7 @@ var _ = Describe("Request Logger", func() { }) }) - When("an error occures while trying to log the request", func() { + When("an error occurs while trying to log the request", func() { var expectedErr error BeforeEach(func() { @@ -373,7 +373,7 @@ var _ = Describe("Request Logger", func() { }) }) - When("an error occures while trying to log the response", func() { + When("an error occurs while trying to log the response", func() { var ( originalErr error expectedErr error diff --git a/api/router/wrapper/request_logger_test.go b/api/router/wrapper/request_logger_test.go index ba361891961..3f7394e6ee7 100644 --- a/api/router/wrapper/request_logger_test.go +++ b/api/router/wrapper/request_logger_test.go @@ -171,7 +171,7 @@ var _ = Describe("Request Logger", func() { }) }) - When("an error occures while trying to log the request", func() { + When("an error occurs while trying to log the request", func() { var expectedErr error BeforeEach(func() { @@ -305,7 +305,7 @@ var _ = Describe("Request Logger", func() { }) }) - When("an error occures while trying to log the response", func() { + When("an error occurs while trying to log the response", func() { var ( originalErr error expectedErr error diff --git a/api/uaa/client_test.go b/api/uaa/client_test.go index 57afc6ee855..4e664c61922 100644 --- a/api/uaa/client_test.go +++ b/api/uaa/client_test.go @@ -51,7 +51,7 @@ var _ = Describe("UAA Client", func() { }) }) - Describe("Conection", func() { + Describe("Connection", func() { BeforeEach(func() { server.AppendHandlers( CombineHandlers( diff --git a/api/uaa/errors.go b/api/uaa/errors.go index 0fdd4287415..c4e9d2815f3 100644 --- a/api/uaa/errors.go +++ b/api/uaa/errors.go @@ -52,7 +52,7 @@ func (e RequestError) Error() string { return e.Err.Error() } -// UnauthorizedError is returned when the authentication informatin is invalid. +// UnauthorizedError is returned when the authentication information is invalid. type UnauthorizedError struct { Message string } @@ -80,7 +80,7 @@ func (e InsufficientScopeError) Error() string { return e.Message } -// InvalidSCIMResourceError is returned usually when the client tries to create an inproperly formatted username +// InvalidSCIMResourceError is returned usually when the client tries to create an improperly formatted username type InvalidSCIMResourceError struct { Message string } diff --git a/api/uaa/internal/routing.go b/api/uaa/internal/routing.go index 7c1fcad0856..7bdbba163d7 100644 --- a/api/uaa/internal/routing.go +++ b/api/uaa/internal/routing.go @@ -12,7 +12,7 @@ import ( // Params map path keys to values. For example, if your route has the path // pattern: // /person/:person_id/pets/:pet_type -// Then a correct Params map would lool like: +// Then a correct Params map would look like: // router.Params{ // "person_id": "123", // "pet_type": "cats", diff --git a/api/uaa/wrapper/request_logger_test.go b/api/uaa/wrapper/request_logger_test.go index bd19d6455a6..553349704fc 100644 --- a/api/uaa/wrapper/request_logger_test.go +++ b/api/uaa/wrapper/request_logger_test.go @@ -195,7 +195,7 @@ var _ = Describe("Request Logger", func() { }) }) - When("an error occures while trying to log the request", func() { + When("an error occurs while trying to log the request", func() { var expectedErr error BeforeEach(func() { @@ -329,7 +329,7 @@ var _ = Describe("Request Logger", func() { }) }) - When("an error occures while trying to log the response", func() { + When("an error occurs while trying to log the response", func() { var ( originalErr error expectedErr error diff --git a/cf/actors/brokerbuilder/broker_builder_test.go b/cf/actors/brokerbuilder/broker_builder_test.go index 174b7e11c9c..94590c76c43 100644 --- a/cf/actors/brokerbuilder/broker_builder_test.go +++ b/cf/actors/brokerbuilder/broker_builder_test.go @@ -225,7 +225,7 @@ var _ = Describe("Broker Builder", func() { }) Describe(".GetBrokerWithSpecifiedService", func() { - It("returns an error if a broker containeing the specific service cannot be found", func() { + It("returns an error if a broker containing the specific service cannot be found", func() { serviceBuilder.GetServiceByNameWithPlansWithOrgNamesReturns(models.ServiceOffering{}, errors.New("Asplosions")) _, err := brokerBuilder.GetBrokerWithSpecifiedService("totally-not-a-service") diff --git a/cf/actors/plugininstaller/plugin_installer_with_repo.go b/cf/actors/plugininstaller/plugin_installer_with_repo.go index e089a4ebc37..50845ff4a27 100644 --- a/cf/actors/plugininstaller/plugin_installer_with_repo.go +++ b/cf/actors/plugininstaller/plugin_installer_with_repo.go @@ -41,7 +41,7 @@ func (installer *pluginInstallerWithRepo) Install(inputSourceFilepath string) st found := false sha1 := "" - for _, plugin := range findRepoCaseInsensity(pluginList, installer.RepoName) { + for _, plugin := range findRepoCaseIntensity(pluginList, installer.RepoName) { if strings.ToLower(plugin.Name) == targetPluginName { found = true outputSourceFilepath, sha1 = installer.PluginDownloader.downloadFromPlugin(plugin) @@ -73,7 +73,7 @@ func (installer *pluginInstallerWithRepo) getRepoFromConfig(repoName string) (mo return models.PluginRepo{}, errors.New(repoName + T(" not found")) } -func findRepoCaseInsensity(repoList map[string][]clipr.Plugin, repoName string) []clipr.Plugin { +func findRepoCaseIntensity(repoList map[string][]clipr.Plugin, repoName string) []clipr.Plugin { target := strings.ToLower(repoName) for k, repo := range repoList { if strings.ToLower(k) == target { diff --git a/cf/api/appinstances/app_instances_test.go b/cf/api/appinstances/app_instances_test.go index cdd41922769..b3223d37544 100644 --- a/cf/api/appinstances/app_instances_test.go +++ b/cf/api/appinstances/app_instances_test.go @@ -64,7 +64,7 @@ var _ = Describe("AppInstancesRepo", func() { It("returns the error if the response is unsuccessful", func() { ts, handler, repo := createAppInstancesRepo([]testnet.TestRequest{ - deleteInstanceFromUnkownApp, + deleteInstanceFromUnknownApp, }) defer ts.Close() appGUID := "some-wrong-app-guid" @@ -128,7 +128,7 @@ var deleteInstanceRequest = apifakes.NewCloudControllerTestRequest(testnet.TestR Response: testnet.TestResponse{Status: http.StatusNoContent, Body: `{}`}, }) -var deleteInstanceFromUnkownApp = apifakes.NewCloudControllerTestRequest(testnet.TestRequest{ +var deleteInstanceFromUnknownApp = apifakes.NewCloudControllerTestRequest(testnet.TestRequest{ Method: "DELETE", Path: "/v2/apps/some-wrong-app-guid/instances/0", Response: testnet.TestResponse{Status: http.StatusNotFound, Body: `{}`}, diff --git a/cf/api/featureflags/feature_flags_test.go b/cf/api/featureflags/feature_flags_test.go index 0ade82cca6e..de9e378f571 100644 --- a/cf/api/featureflags/feature_flags_test.go +++ b/cf/api/featureflags/feature_flags_test.go @@ -92,7 +92,7 @@ var _ = Describe("Feature Flags Repository", func() { Expect(err).ToNot(HaveOccurred()) }) - Context("when given a non-existent feature flag", func() { + Context("when given a nonexistent feature flag", func() { BeforeEach(func() { setupTestServer(featureFlagsUpdateErrorRequest) }) diff --git a/cf/api/organizations/organizations_test.go b/cf/api/organizations/organizations_test.go index ce3e458c910..c1eecc5f709 100644 --- a/cf/api/organizations/organizations_test.go +++ b/cf/api/organizations/organizations_test.go @@ -107,7 +107,7 @@ var _ = Describe("Organization Repository", func() { Expect(len(orgs)).To(Equal(3)) }) - It("lists the orgs from the the /v2/orgs endpoint in alphabetical order", func() { + It("lists the orgs from the /v2/orgs endpoint in alphabetical order", func() { orgs, apiErr := repo.ListOrgs(0) Expect(len(orgs)).To(Equal(3)) diff --git a/cf/appfiles/cf_ignore_test.go b/cf/appfiles/cf_ignore_test.go index 5f10e52377f..2814771fbcf 100644 --- a/cf/appfiles/cf_ignore_test.go +++ b/cf/appfiles/cf_ignore_test.go @@ -59,7 +59,7 @@ stuff/exclude.c`) Expect(ignore.FileShouldBeIgnored("stuff/include.c")).To(BeFalse()) }) - It("ignores certain commonly ingored files by default", func() { + It("ignores certain commonly ignored files by default", func() { ignore := NewCfIgnore(``) Expect(ignore.FileShouldBeIgnored(".git/objects")).To(BeTrue()) diff --git a/cf/commandregistry/dependency_test.go b/cf/commandregistry/dependency_test.go index 50879fbee8e..4f93d0ca41f 100644 --- a/cf/commandregistry/dependency_test.go +++ b/cf/commandregistry/dependency_test.go @@ -13,7 +13,7 @@ import ( var _ = Describe("Dependency", func() { var dependency commandregistry.Dependency - It("populates all fields by calling all the dependency contructors", func() { + It("populates all fields by calling all the dependency constructors", func() { fakeLogger := new(tracefakes.FakePrinter) dependency = commandregistry.NewDependency(os.Stdout, fakeLogger, "") diff --git a/cf/commands/application/apps_test.go b/cf/commands/application/apps_test.go index 1e12c35cbca..aaaebb32d59 100644 --- a/cf/commands/application/apps_test.go +++ b/cf/commands/application/apps_test.go @@ -197,7 +197,7 @@ var _ = Describe("list-apps command", func() { }) Context("when an app's running instances is unknown", func() { - It("dipslays a '?' for running instances", func() { + It("displays a '?' for running instances", func() { appRoutes := []models.RouteSummary{ { Host: "app1", diff --git a/cf/commands/application/copy_source_test.go b/cf/commands/application/copy_source_test.go index 5c7fb941e68..1d72044b8bf 100644 --- a/cf/commands/application/copy_source_test.go +++ b/cf/commands/application/copy_source_test.go @@ -203,7 +203,7 @@ var _ = Describe("CopySource", func() { }) Describe("when a space is provided, but not an org", func() { - It("sends the correct target appplication for the current org and target space", func() { + It("sends the correct target application for the current org and target space", func() { space := models.Space{} space.Name = "space-name" space.GUID = "model-space-guid" diff --git a/cf/commands/application/push_test.go b/cf/commands/application/push_test.go index 4ef5a3c067a..89cad1e5020 100644 --- a/cf/commands/application/push_test.go +++ b/cf/commands/application/push_test.go @@ -1764,7 +1764,7 @@ var _ = Describe("Push Command", func() { args = []string{"--no-hostname", "existing-app"} }) - It("binds the root domain route to an app with a pre-existing route", func() { + It("binds the root domain route to an app with a preexisting route", func() { Expect(executeErr).NotTo(HaveOccurred()) Expect(routeActor.FindOrCreateRouteCallCount()).To(Equal(1)) diff --git a/cf/commands/application/ssh_test.go b/cf/commands/application/ssh_test.go index fe631c61fee..d12164f3bb9 100644 --- a/cf/commands/application/ssh_test.go +++ b/cf/commands/application/ssh_test.go @@ -281,7 +281,7 @@ var _ = Describe("SSH command", func() { Context("Error when connecting", func() { It("notifies users", func() { - fakeSecureShell.ConnectReturns(errors.New("dial errorrr")) + fakeSecureShell.ConnectReturns(errors.New("dial error")) runCommand("my-app") diff --git a/cf/commands/buildpack/delete_buildpack_test.go b/cf/commands/buildpack/delete_buildpack_test.go index 26b10588c77..119c8d34872 100644 --- a/cf/commands/buildpack/delete_buildpack_test.go +++ b/cf/commands/buildpack/delete_buildpack_test.go @@ -79,7 +79,7 @@ var _ = Describe("delete-buildpack command", func() { }) Context("when the force flag is provided", func() { - It("does not prompt the user to delete the buildback", func() { + It("does not prompt the user to delete the buildpack", func() { runCommand("-f", "my-buildpack") Expect(buildpackRepo.DeleteBuildpackGUID).To(Equal("my-buildpack-guid")) diff --git a/cf/commands/config_test.go b/cf/commands/config_test.go index e758ddc0681..1b1c3a28d8a 100644 --- a/cf/commands/config_test.go +++ b/cf/commands/config_test.go @@ -57,7 +57,7 @@ var _ = Describe("config command", func() { )) }) - It("fails with usage when a negative timout is passed", func() { + It("fails with usage when a negative timeout is passed", func() { runCommand("--async-timeout", "-555") Expect(ui.Outputs()).To(ContainSubstrings( []string{"Incorrect Usage"}, diff --git a/cf/commands/curl_test.go b/cf/commands/curl_test.go index 1f62002b1ef..7d046d21f89 100644 --- a/cf/commands/curl_test.go +++ b/cf/commands/curl_test.go @@ -148,7 +148,7 @@ var _ = Describe("curl command", func() { Expect(ui.Outputs()).To(ContainSubstrings([]string{"The requested URL returned error: 500"})) }) - It("does not fail on HTTP erros if --fail is false", func() { + It("does not fail on HTTP errors if --fail is false", func() { runCurlWithInputs([]string{"--fail", "false", "/foo"}) Expect(curlRepo.FailOnHTTPError).To(Equal(false)) diff --git a/cf/commands/domain/delete_shared_domain_test.go b/cf/commands/domain/delete_shared_domain_test.go index 284406cb954..6b23eedb0ba 100644 --- a/cf/commands/domain/delete_shared_domain_test.go +++ b/cf/commands/domain/delete_shared_domain_test.go @@ -50,7 +50,7 @@ var _ = Describe("delete-shared-domain command", func() { Expect(runCommand("foo.com")).To(BeFalse()) }) - It("fails if an organiztion is not targeted", func() { + It("fails if an organization is not targeted", func() { requirementsFactory.NewLoginRequirementReturns(requirements.Passing{}) targetedOrganizationReq := new(requirementsfakes.FakeTargetedOrgRequirement) @@ -86,7 +86,7 @@ var _ = Describe("delete-shared-domain command", func() { }) }) - Context("when logged in and targeted an organiztion", func() { + Context("when logged in and targeted an organization", func() { BeforeEach(func() { requirementsFactory.NewLoginRequirementReturns(requirements.Passing{}) requirementsFactory.NewTargetedOrgRequirementReturns(new(requirementsfakes.FakeTargetedOrgRequirement)) diff --git a/cf/commands/login_test.go b/cf/commands/login_test.go index 88993b7e210..bde9d340e28 100644 --- a/cf/commands/login_test.go +++ b/cf/commands/login_test.go @@ -760,7 +760,7 @@ var _ = Describe("Login Command", func() { }) }) - Describe("and the login fails authenticaton", func() { + Describe("and the login fails authentication", func() { BeforeEach(func() { authRepo.AuthenticateReturns(errors.New("Error authenticating.")) diff --git a/cf/commands/organization/create_org_test.go b/cf/commands/organization/create_org_test.go index d07907e6867..a966a80ffe2 100644 --- a/cf/commands/organization/create_org_test.go +++ b/cf/commands/organization/create_org_test.go @@ -187,7 +187,7 @@ var _ = Describe("create-org command", func() { }) }) - Context("when allowing a non-defualt quota", func() { + Context("when allowing a non-default quota", func() { var ( quota models.QuotaFields ) diff --git a/cf/commands/plugin/install_plugin_test.go b/cf/commands/plugin/install_plugin_test.go index b0b3539a328..c091716e8a8 100644 --- a/cf/commands/plugin/install_plugin_test.go +++ b/cf/commands/plugin/install_plugin_test.go @@ -111,7 +111,7 @@ var _ = Describe("Install", func() { }) runCommand := func(args ...string) bool { - // run command has races becuase it writes and erases temporary files, so the test runner should + // run command has races because it writes and erases temporary files, so the test runner should // really only run one of these at a time. Often the files are actual compiled exes in the test // fixtures path, so it's not easy to prevent the tests from sharing file handles runCmdMutex.Lock() diff --git a/cf/commands/pluginrepo/add_plugin_repo_test.go b/cf/commands/pluginrepo/add_plugin_repo_test.go index 2fd73ad6bc8..81cc767e637 100644 --- a/cf/commands/pluginrepo/add_plugin_repo_test.go +++ b/cf/commands/pluginrepo/add_plugin_repo_test.go @@ -191,7 +191,7 @@ var _ = Describe("add-plugin-repo", func() { Context("When connection could not be established", func() { It("prints a tip", func() { - callAddPluginRepo([]string{"repo", "https://broccoli.nonexistanttld:"}) + callAddPluginRepo([]string{"repo", "https://broccoli.nonexistenttld:"}) Expect(ui.Outputs()).To(ContainSubstrings( []string{"TIP: If you are behind a firewall and require an HTTP proxy, verify the https_proxy environment variable is correctly set. Else, check your network connection."}, diff --git a/cf/commands/pluginrepo/remove_plugin_repo_test.go b/cf/commands/pluginrepo/remove_plugin_repo_test.go index 7f181d2849f..a1241d3ff26 100644 --- a/cf/commands/pluginrepo/remove_plugin_repo_test.go +++ b/cf/commands/pluginrepo/remove_plugin_repo_test.go @@ -15,7 +15,7 @@ import ( . "github.com/onsi/gomega" ) -var _ = Describe("delte-plugin-repo", func() { +var _ = Describe("delete-plugin-repo", func() { var ( ui *testterm.FakeUI config coreconfig.Repository diff --git a/cf/commands/quota/delete_quota_test.go b/cf/commands/quota/delete_quota_test.go index 15d7712d8c6..f3fb67788a3 100644 --- a/cf/commands/quota/delete_quota_test.go +++ b/cf/commands/quota/delete_quota_test.go @@ -114,19 +114,19 @@ var _ = Describe("delete-quota command", func() { Context("when finding the quota fails", func() { Context("when the quota provided does not exist", func() { BeforeEach(func() { - quotaRepo.FindByNameReturns(models.QuotaFields{}, errors.NewModelNotFoundError("Quota", "non-existent-quota")) + quotaRepo.FindByNameReturns(models.QuotaFields{}, errors.NewModelNotFoundError("Quota", "nonexistent-quota")) }) It("warns the user when that the quota does not exist", func() { - runCommand("-f", "non-existent-quota") + runCommand("-f", "nonexistent-quota") Expect(ui.Outputs()).To(ContainSubstrings( - []string{"Deleting", "non-existent-quota"}, + []string{"Deleting", "nonexistent-quota"}, []string{"OK"}, )) Expect(ui.WarnOutputs).To(ContainSubstrings( - []string{"non-existent-quota", "does not exist"}, + []string{"nonexistent-quota", "does not exist"}, )) }) }) diff --git a/cf/commands/securitygroup/create_security_group_test.go b/cf/commands/securitygroup/create_security_group_test.go index 38e7b62a920..92bd672b3a2 100644 --- a/cf/commands/securitygroup/create_security_group_test.go +++ b/cf/commands/securitygroup/create_security_group_test.go @@ -141,7 +141,7 @@ var _ = Describe("create-security-group command", func() { Expect(ui.Outputs()).To(ContainSubstrings( []string{"FAILED"}, []string{"Incorrect json format: file:", tempFile.Name()}, - []string{"Valid json file exampl"}, + []string{"Valid json file example"}, )) }) }) diff --git a/cf/commands/service/create_service_test.go b/cf/commands/service/create_service_test.go index cc620d91a04..43b3e41798f 100644 --- a/cf/commands/service/create_service_test.go +++ b/cf/commands/service/create_service_test.go @@ -109,7 +109,7 @@ var _ = Describe("create-service command", func() { }) Context("when passing in tags", func() { - It("sucessfully creates a service and passes the tags as json", func() { + It("successfully creates a service and passes the tags as json", func() { callCreateService([]string{"cleardb", "spark", "my-cleardb-service", "-t", "tag1, tag2,tag3, tag4"}) Expect(ui.Outputs()).To(ContainSubstrings( @@ -252,7 +252,7 @@ var _ = Describe("create-service command", func() { []string{"Creating service instance", "my-free-cleardb-service", "my-org", "my-space", "my-user"}, []string{"OK"}, )) - Expect(ui.Outputs()).NotTo(ContainSubstrings([]string{"will incurr a cost"})) + Expect(ui.Outputs()).NotTo(ContainSubstrings([]string{"will incur a cost"})) }) It("warns the user when the service is not free", func() { diff --git a/cf/commands/service/create_user_provided_service_test.go b/cf/commands/service/create_user_provided_service_test.go index 60831dbfa0d..4095c0d0353 100644 --- a/cf/commands/service/create_user_provided_service_test.go +++ b/cf/commands/service/create_user_provided_service_test.go @@ -277,7 +277,7 @@ var _ = Describe("CreateUserProvidedService", func() { flagContext.Parse("service-instance", "-t", "tag1, tag2, tag3, tag4") }) - It("sucessfully creates a service instance and passes the tags as json", func() { + It("successfully creates a service instance and passes the tags as json", func() { Expect(runCLIErr).NotTo(HaveOccurred()) Expect(serviceInstanceRepo.CreateCallCount()).To(Equal(1)) _, _, _, _, tags := serviceInstanceRepo.CreateArgsForCall(0) diff --git a/cf/commands/service/unbind_service_test.go b/cf/commands/service/unbind_service_test.go index f90c2910cbb..e8d479d2dde 100644 --- a/cf/commands/service/unbind_service_test.go +++ b/cf/commands/service/unbind_service_test.go @@ -99,7 +99,7 @@ var _ = Describe("unbind-service command", func() { serviceBindingRepo.DeleteReturns(false, nil) }) - It("warns the user the the service instance does not exist", func() { + It("warns the user the service instance does not exist", func() { callUnbindService([]string{"my-app", "my-service"}) Expect(ui.Outputs()).To(ContainSubstrings( diff --git a/cf/commands/service/update_user_provided_service_test.go b/cf/commands/service/update_user_provided_service_test.go index 962f397e0a9..d46c385c52a 100644 --- a/cf/commands/service/update_user_provided_service_test.go +++ b/cf/commands/service/update_user_provided_service_test.go @@ -275,7 +275,7 @@ var _ = Describe("UpdateUserProvidedService", func() { flagContext.Parse("service-instance", "-t", "tag1, tag2, tag3, tag4") }) - It("sucessfully updates the service instance and passes the tags as json", func() { + It("successfully updates the service instance and passes the tags as json", func() { Expect(runCLIErr).NotTo(HaveOccurred()) Expect(serviceInstanceRepo.UpdateCallCount()).To(Equal(1)) serviceInstanceFields := serviceInstanceRepo.UpdateArgsForCall(0) diff --git a/cf/commands/serviceaccess/disable_service_access_test.go b/cf/commands/serviceaccess/disable_service_access_test.go index e9d7fc026c4..c648781dea3 100644 --- a/cf/commands/serviceaccess/disable_service_access_test.go +++ b/cf/commands/serviceaccess/disable_service_access_test.go @@ -60,7 +60,7 @@ var _ = Describe("disable-service-access command", func() { Expect(runCommand([]string{"foo"})).To(BeFalse()) }) - It("fails with usage when it does not recieve any arguments", func() { + It("fails with usage when it does not receive any arguments", func() { requirementsFactory.NewLoginRequirementReturns(requirements.Passing{}) runCommand(nil) Expect(ui.Outputs()).To(ContainSubstrings( diff --git a/cf/commands/serviceaccess/enable_service_access_test.go b/cf/commands/serviceaccess/enable_service_access_test.go index a0fbdeb0334..298687999b3 100644 --- a/cf/commands/serviceaccess/enable_service_access_test.go +++ b/cf/commands/serviceaccess/enable_service_access_test.go @@ -59,7 +59,7 @@ var _ = Describe("enable-service-access command", func() { Expect(runCommand([]string{"foo"})).To(BeFalse()) }) - It("fails with usage when it does not recieve any arguments", func() { + It("fails with usage when it does not receive any arguments", func() { requirementsFactory.NewLoginRequirementReturns(requirements.Passing{}) runCommand(nil) Expect(ui.Outputs()).To(ContainSubstrings( diff --git a/cf/commands/spacequota/create_space_quota_test.go b/cf/commands/spacequota/create_space_quota_test.go index 50ae6dcb3e1..112d85d3e4d 100644 --- a/cf/commands/spacequota/create_space_quota_test.go +++ b/cf/commands/spacequota/create_space_quota_test.go @@ -143,7 +143,7 @@ var _ = Describe("create-space-quota", func() { )) }) - It("sets the instance memory limit to unlimiited", func() { + It("sets the instance memory limit to unlimited", func() { Expect(quotaRepo.CreateArgsForCall(0).InstanceMemoryLimit).To(Equal(int64(-1))) }) @@ -272,7 +272,7 @@ var _ = Describe("create-space-quota", func() { cmd.SetDependency(deps, false) }) - It("alets the user when creating the quota fails", func() { + It("alerts the user when creating the quota fails", func() { Expect(runCLIErr).To(HaveOccurred()) Expect(ui.Outputs()).To(ContainSubstrings( []string{"Creating space quota", "my-quota", "my-org"}, diff --git a/cf/commands/spacequota/delete_space_quota_test.go b/cf/commands/spacequota/delete_space_quota_test.go index db65d8fc42b..b7737ea5483 100644 --- a/cf/commands/spacequota/delete_space_quota_test.go +++ b/cf/commands/spacequota/delete_space_quota_test.go @@ -129,19 +129,19 @@ var _ = Describe("delete-space-quota command", func() { Context("when finding the quota fails", func() { Context("when the quota provided does not exist", func() { BeforeEach(func() { - quotaRepo.FindByNameReturns(models.SpaceQuota{}, errors.NewModelNotFoundError("Quota", "non-existent-quota")) + quotaRepo.FindByNameReturns(models.SpaceQuota{}, errors.NewModelNotFoundError("Quota", "nonexistent-quota")) }) It("warns the user when that the quota does not exist", func() { - runCommand("-f", "non-existent-quota") + runCommand("-f", "nonexistent-quota") Expect(ui.Outputs()).To(ContainSubstrings( - []string{"Deleting", "non-existent-quota"}, + []string{"Deleting", "nonexistent-quota"}, []string{"OK"}, )) Expect(ui.WarnOutputs).To(ContainSubstrings( - []string{"non-existent-quota", "does not exist"}, + []string{"nonexistent-quota", "does not exist"}, )) }) }) diff --git a/cf/commands/user/delete_user_test.go b/cf/commands/user/delete_user_test.go index 1359ec124e7..0677a42aa78 100644 --- a/cf/commands/user/delete_user_test.go +++ b/cf/commands/user/delete_user_test.go @@ -124,7 +124,7 @@ var _ = Describe("delete-user command", func() { }, nil) }) - It("returns a muliple users found error", func() { + It("returns a multiple users found error", func() { runCommand("user-name") Expect(ui.Outputs()).To(ContainSubstrings( diff --git a/cf/commands/user/org_users_test.go b/cf/commands/user/org_users_test.go index 0866fe1952e..7ead8a1c292 100644 --- a/cf/commands/user/org_users_test.go +++ b/cf/commands/user/org_users_test.go @@ -85,7 +85,7 @@ var _ = Describe("org-users command", func() { requirementsFactory.NewOrganizationRequirementReturns(organizationReq) }) - Context("shows friendly messaage when no users in ORG_MANAGER role", func() { + Context("shows friendly message when no users in ORG_MANAGER role", func() { It("shows the special users in the given org", func() { userRepo.ListUsersInOrgForRoleWithNoUAAStub = func(_ string, roleName models.Role) ([]models.UserFields, error) { userFields := map[models.Role][]models.UserFields{ @@ -117,7 +117,7 @@ var _ = Describe("org-users command", func() { }) }) - Context("shows friendly messaage when no users in BILLING_MANAGER role", func() { + Context("shows friendly message when no users in BILLING_MANAGER role", func() { It("shows the special users in the given org", func() { userRepo.ListUsersInOrgForRoleWithNoUAAStub = func(_ string, roleName models.Role) ([]models.UserFields, error) { userFields := map[models.Role][]models.UserFields{ @@ -149,7 +149,7 @@ var _ = Describe("org-users command", func() { }) }) - Context("shows friendly messaage when no users in ORG_AUDITOR role", func() { + Context("shows friendly message when no users in ORG_AUDITOR role", func() { It("shows the special users in the given org", func() { userRepo.ListUsersInOrgForRoleWithNoUAAStub = func(_ string, roleName models.Role) ([]models.UserFields, error) { userFields := map[models.Role][]models.UserFields{ diff --git a/cf/flags/flags_test.go b/cf/flags/flags_test.go index 1b29cd2978e..14acb4efe9d 100644 --- a/cf/flags/flags_test.go +++ b/cf/flags/flags_test.go @@ -8,7 +8,7 @@ import ( var _ = Describe("Flags", func() { Describe("FlagContext", func() { - Describe("Parsing and retriving values", func() { + Describe("Parsing and retrieving values", func() { var ( fCtx flags.FlagContext cmdFlagMap map[string]flags.FlagSet @@ -73,7 +73,7 @@ var _ = Describe("Flags", func() { Ω(fCtx.Bool("skip2")).To(Equal(true), "skip2 should be true") Ω(fCtx.Bool("name")).To(Equal(false), "name should be false") Ω(fCtx.String("name")).To(Equal("johndoe"), "name should be johndoe") - Expect(fCtx.Bool("non-exisit-flag")).To(Equal(false)) + Expect(fCtx.Bool("non-exist-flag")).To(Equal(false)) }) It("sets Bool() to return true if bool flag is provided with invalid value", func() { @@ -90,7 +90,7 @@ var _ = Describe("Flags", func() { Ω(fCtx.Bool("skip")).To(Equal(true), "skip should be true") Ω(fCtx.Bool("name")).To(Equal(false), "name should be false") - Expect(fCtx.Bool("non-exisit-flag")).To(Equal(false)) + Expect(fCtx.Bool("non-exist-flag")).To(Equal(false)) }) It("sets String() to return provided value when a string flag is provided", func() { diff --git a/cf/i18n/README-i18n.md b/cf/i18n/README-i18n.md index 6b4e1d5a9d2..097e568d823 100644 --- a/cf/i18n/README-i18n.md +++ b/cf/i18n/README-i18n.md @@ -8,7 +8,7 @@ If you are interested in submitting translations for a currently unsupported lan ## How can you contribute? -If you see typos, errors in grammar, ambiguous strings or English after setting your locale, please find the appropriate entry in the corresponding `i18n/resources/_.all.json` file and submit a [pull request](https://help.github.com/articles/creating-a-pull-request/) with the fix(es). It is much better to submit small pull requests as you complete translations, rather than submitting a large one. This makes it much easier to rapidly merge your changes in. You can also report translations needing fixes as an issue in Github. +If you see typos, errors in grammar, ambiguous strings or English after setting your locale, please find the appropriate entry in the corresponding `i18n/resources/_.all.json` file and submit a [pull request](https://help.github.com/articles/creating-a-pull-request/) with the fix(es). It is much better to submit small pull requests as you complete translations, rather than submitting a large one. This makes it much easier to rapidly merge your changes in. You can also report translations needing fixes as an issue in GitHub. Pull requests should only contain changes to "translation" values; the "id" value should not change as it is the key which is used to find the translations, and will always be English. For example: diff --git a/cf/ssh/options/ssh_options_test.go b/cf/ssh/options/ssh_options_test.go index b4fe1f8d25d..4f77b1dd700 100644 --- a/cf/ssh/options/ssh_options_test.go +++ b/cf/ssh/options/ssh_options_test.go @@ -121,7 +121,7 @@ var _ = Describe("SSHOptions", func() { BeforeEach(func() { args = append(args, "app-name", "-tt") }) - It("foces tty allocation", func() { + It("forces tty allocation", func() { Expect(opts.TerminalRequest).To(Equal(options.RequestTTYForce)) }) }) @@ -190,7 +190,7 @@ var _ = Describe("SSHOptions", func() { }) }) - Context("with an explit bind address", func() { + Context("with an explicit bind address", func() { BeforeEach(func() { args = append(args, "-L", "explicit:9999:remote:8888") }) diff --git a/cf/ssh/ssh_test.go b/cf/ssh/ssh_test.go index 521e76cea89..60f6dad838b 100644 --- a/cf/ssh/ssh_test.go +++ b/cf/ssh/ssh_test.go @@ -481,7 +481,7 @@ var _ = Describe("SSH", func() { Expect(fakeSecureSession.ShellCallCount()).To(Equal(1)) }) - It("does not not restore the terminal", func() { + It("does not restore the terminal", func() { Expect(fakeSecureSession.ShellCallCount()).To(Equal(1)) Expect(fakeTerminalHelper.SetRawTerminalCallCount()).To(Equal(1)) Expect(fakeTerminalHelper.RestoreTerminalCallCount()).To(Equal(0)) @@ -581,7 +581,7 @@ var _ = Describe("SSH", func() { }) }) - Context("when a command is specifed", func() { + Context("when a command is specified", func() { BeforeEach(func() { opts.Command = []string{"echo", "-n", "hello"} }) diff --git a/cf/terminal/table.go b/cf/terminal/table.go index a123e3ff310..debd10d19a5 100644 --- a/cf/terminal/table.go +++ b/cf/terminal/table.go @@ -174,7 +174,7 @@ func (t *Table) calculateMaxSize(transformer rowTransformer, rowIndex int, row [ return nil } -// printRow is responsible for the layouting, transforming and +// printRow is responsible for the laying-out, transforming and // printing of the string in a single row func (t *Table) printRow(result io.Writer, transformer rowTransformer, rowIndex int, row []string) error { @@ -255,7 +255,7 @@ func (t *Table) printRow(result io.Writer, transformer rowTransformer, rowIndex } // printCellValue pads the specified string to the width of the given -// column, adds the spacing bewtween columns, and returns the result. +// column, adds the spacing between columns, and returns the result. func (t *Table) printCellValue(result io.Writer, transformer rowTransformer, col, last int, value string) error { value = trim(transformer.Transform(col, trim(value))) fmt.Fprint(result, value) diff --git a/cf/util/downloader/file_download_test.go b/cf/util/downloader/file_download_test.go index 2665771ddaf..64fb2a4e6d9 100644 --- a/cf/util/downloader/file_download_test.go +++ b/cf/util/downloader/file_download_test.go @@ -154,7 +154,7 @@ var _ = Describe("Downloader", func() { Context("when the URL is invalid", func() { It("returns an error", func() { - _, _, err := d.DownloadFile("http://going.nowwhere/abc.zip") + _, _, err := d.DownloadFile("http://going.nowhere/abc.zip") Expect(err).To(HaveOccurred()) }) }) diff --git a/cf/util/testhelpers/io/io.go b/cf/util/testhelpers/io/io.go index df710d856f8..571232151d4 100644 --- a/cf/util/testhelpers/io/io.go +++ b/cf/util/testhelpers/io/io.go @@ -50,7 +50,7 @@ func CaptureOutput(block func()) []string { doneWriting := make(chan bool) result := make(chan []string) - go captureOutputAsyncronously(doneWriting, result, r) + go captureOutputAsynchronously(doneWriting, result, r) block() w.Close() @@ -64,7 +64,7 @@ func CaptureOutput(block func()) []string { (looking at you, Windows). To counteract this, we need to read in a goroutine from one end of the pipe and return the result across a channel. */ -func captureOutputAsyncronously(doneWriting <-chan bool, result chan<- []string, reader io.Reader) { +func captureOutputAsynchronously(doneWriting <-chan bool, result chan<- []string, reader io.Reader) { var readingString string for { diff --git a/cf/util/testhelpers/matchers/match_func_name_test.go b/cf/util/testhelpers/matchers/match_func_name_test.go index 604b740d90b..c5b6e942c87 100644 --- a/cf/util/testhelpers/matchers/match_func_name_test.go +++ b/cf/util/testhelpers/matchers/match_func_name_test.go @@ -99,7 +99,7 @@ var _ = Describe("MatchChangeAppFuncsByName", func() { }) }) - Describe("NegatedFaileureMessage", func() { + Describe("NegatedFailureMessage", func() { It("shows expected and actual", func() { matcher = MatchFuncsByName(dummyFunc) matcher.Match([]func(){dummyNotMatchFunc}) diff --git a/cf/util/testhelpers/net/server.go b/cf/util/testhelpers/net/server.go index 79be4b70c83..09ce8e811c3 100644 --- a/cf/util/testhelpers/net/server.go +++ b/cf/util/testhelpers/net/server.go @@ -41,7 +41,7 @@ func urlQueryContains(container, containee url.Values) bool { //Example: "foo:bar;baz:qux" is semantically the same as "baz:qux;foo:bar". CC doesn't care about order. - //Therefore, we crack apart "q" params on their seperator (a colon) and compare the resulting + //Therefore, we crack apart "q" params on their separator (a colon) and compare the resulting //substrings. No other params seem to use semicolon separators AND are order-dependent, so we just //run all params through the same process. for key := range containee { diff --git a/command/common/install_plugin_command.go b/command/common/install_plugin_command.go index e38fa3864e2..16a51682fad 100644 --- a/command/common/install_plugin_command.go +++ b/command/common/install_plugin_command.go @@ -407,7 +407,7 @@ func (cmd InstallPluginCommand) installPluginPrompt(template string, templateVal } if !really { - log.Debug("plugin confirmation - 'no' inputed") + log.Debug("plugin confirmation - 'no' inputted") return cancelInstall{} } diff --git a/command/common/install_plugin_from_repo_command_test.go b/command/common/install_plugin_from_repo_command_test.go index a92a4de9f9e..11fe6bd9e80 100644 --- a/command/common/install_plugin_from_repo_command_test.go +++ b/command/common/install_plugin_from_repo_command_test.go @@ -307,7 +307,7 @@ var _ = Describe("install-plugin command", func() { }) }) - When("creating an exectuable copy succeeds", func() { + When("creating an executable copy succeeds", func() { BeforeEach(func() { fakeActor.CreateExecutableCopyReturns("copy-path", nil) }) diff --git a/command/v7/add_network_policy_command_test.go b/command/v7/add_network_policy_command_test.go index 998afb510c9..90e9a0160de 100644 --- a/command/v7/add_network_policy_command_test.go +++ b/command/v7/add_network_policy_command_test.go @@ -115,7 +115,7 @@ var _ = Describe("add-network-policy Command", func() { }) }) - When("both protocol and port are specificed", func() { + When("both protocol and port are specified", func() { BeforeEach(func() { cmd.Protocol = flag.NetworkProtocol{Protocol: protocol} cmd.Port = flag.NetworkPort{StartPort: 8080, EndPort: 8081} diff --git a/command/v7/auth_command.go b/command/v7/auth_command.go index 6b787b3245f..0d5f70c4702 100644 --- a/command/v7/auth_command.go +++ b/command/v7/auth_command.go @@ -18,7 +18,7 @@ type AuthCommand struct { RequiredArgs flag.Authentication `positional-args:"yes"` ClientCredentials bool `long:"client-credentials" description:"Use (non-user) service account (also called client credentials)"` Origin string `long:"origin" description:"Indicates the identity provider to be used for authentication"` - usage interface{} `usage:"CF_NAME auth USERNAME PASSWORD\n CF_NAME auth USERNAME PASSWORD --origin ORIGIN\n CF_NAME auth CLIENT_ID CLIENT_SECRET --client-credentials\n\nENVIRONMENT VARIABLES:\n CF_USERNAME=user Authenticating user. Overridden if USERNAME argument is provided.\n CF_PASSWORD=password Password associated with user. Overriden if PASSWORD argument is provided.\n\nWARNING:\n Providing your password as a command line option is highly discouraged\n Your password may be visible to others and may be recorded in your shell history\n Consider using the CF_PASSWORD environment variable instead\n\nEXAMPLES:\n CF_NAME auth name@example.com \"my password\" (use quotes for passwords with a space)\n CF_NAME auth name@example.com \"\\\"password\\\"\" (escape quotes if used in password)"` + usage interface{} `usage:"CF_NAME auth USERNAME PASSWORD\n CF_NAME auth USERNAME PASSWORD --origin ORIGIN\n CF_NAME auth CLIENT_ID CLIENT_SECRET --client-credentials\n\nENVIRONMENT VARIABLES:\n CF_USERNAME=user Authenticating user. Overridden if USERNAME argument is provided.\n CF_PASSWORD=password Password associated with user. Overridden if PASSWORD argument is provided.\n\nWARNING:\n Providing your password as a command line option is highly discouraged\n Your password may be visible to others and may be recorded in your shell history\n Consider using the CF_PASSWORD environment variable instead\n\nEXAMPLES:\n CF_NAME auth name@example.com \"my password\" (use quotes for passwords with a space)\n CF_NAME auth name@example.com \"\\\"password\\\"\" (escape quotes if used in password)"` relatedCommands interface{} `related_commands:"api, login, target"` } diff --git a/command/v7/buildpacks_command_test.go b/command/v7/buildpacks_command_test.go index 6dd304e0686..abcf60f2b73 100644 --- a/command/v7/buildpacks_command_test.go +++ b/command/v7/buildpacks_command_test.go @@ -75,7 +75,7 @@ var _ = Describe("buildpacks Command", func() { fakeActor.GetCurrentUserReturns(configv3.User{Name: "apple"}, nil) }) - It("should print text indicating its runnning", func() { + It("should print text indicating its running", func() { Expect(executeErr).NotTo(HaveOccurred()) Expect(testUI.Out).To(Say(`Getting buildpacks as apple\.\.\.`)) }) diff --git a/command/v7/create_app_manifest_command_test.go b/command/v7/create_app_manifest_command_test.go index 23894166f13..6f132cafdc8 100644 --- a/command/v7/create_app_manifest_command_test.go +++ b/command/v7/create_app_manifest_command_test.go @@ -116,7 +116,7 @@ var _ = Describe("create-app-manifest Command", func() { Expect(os.RemoveAll(tempDir)).ToNot(HaveOccurred()) }) - It("creates application manifest in current directry as -manifest.yml", func() { + It("creates application manifest in current directory as -manifest.yml", func() { Expect(executeErr).ToNot(HaveOccurred()) Expect(fakeActor.GetRawApplicationManifestByNameAndSpaceCallCount()).To(Equal(1)) diff --git a/command/v7/curl_command.go b/command/v7/curl_command.go index bddc3cc421b..8f8d3be40d3 100644 --- a/command/v7/curl_command.go +++ b/command/v7/curl_command.go @@ -11,14 +11,14 @@ import ( type CurlCommand struct { BaseCommand - RequiredArgs flag.APIPath `positional-args:"yes"` - CustomHeaders []string `short:"H" description:"Custom headers to include in the request, flag can be specified multiple times"` - HTTPMethod string `short:"X" description:"HTTP method (GET,POST,PUT,DELETE,etc)"` - HTTPData flag.PathWithAt `short:"d" description:"HTTP data to include in the request body, or '@' followed by a file name to read the data from"` - FailOnHTTPError bool `short:"f" long:"fail" description:"Server errors return exit code 22"` - IncludeReponseHeaders bool `short:"i" description:"Include response headers in the output"` - OutputFile flag.Path `long:"output" description:"Write curl body to FILE instead of stdout"` - usage interface{} `usage:"CF_NAME curl PATH [-iv] [-X METHOD] [-H HEADER]... [-d DATA] [--output FILE]\n\n By default 'CF_NAME curl' will perform a GET to the specified PATH. If data\n is provided via -d, a POST will be performed instead, and the Content-Type\n will be set to application/json. You may override headers with -H and the\n request method with -X.\n\n For API documentation, please visit http://apidocs.cloudfoundry.org.\n\nEXAMPLES:\n CF_NAME curl \"/v2/apps\" -X GET -H \"Content-Type: application/x-www-form-urlencoded\" -d 'q=name:myapp'\n CF_NAME curl \"/v2/apps\" -d @/path/to/file"` + RequiredArgs flag.APIPath `positional-args:"yes"` + CustomHeaders []string `short:"H" description:"Custom headers to include in the request, flag can be specified multiple times"` + HTTPMethod string `short:"X" description:"HTTP method (GET,POST,PUT,DELETE,etc)"` + HTTPData flag.PathWithAt `short:"d" description:"HTTP data to include in the request body, or '@' followed by a file name to read the data from"` + FailOnHTTPError bool `short:"f" long:"fail" description:"Server errors return exit code 22"` + IncludeResponseHeaders bool `short:"i" description:"Include response headers in the output"` + OutputFile flag.Path `long:"output" description:"Write curl body to FILE instead of stdout"` + usage interface{} `usage:"CF_NAME curl PATH [-iv] [-X METHOD] [-H HEADER]... [-d DATA] [--output FILE]\n\n By default 'CF_NAME curl' will perform a GET to the specified PATH. If data\n is provided via -d, a POST will be performed instead, and the Content-Type\n will be set to application/json. You may override headers with -H and the\n request method with -X.\n\n For API documentation, please visit http://apidocs.cloudfoundry.org.\n\nEXAMPLES:\n CF_NAME curl \"/v2/apps\" -X GET -H \"Content-Type: application/x-www-form-urlencoded\" -d 'q=name:myapp'\n CF_NAME curl \"/v2/apps\" -d @/path/to/file"` } func (cmd CurlCommand) Execute(args []string) error { @@ -40,7 +40,7 @@ func (cmd CurlCommand) Execute(args []string) error { var bytesToWrite []byte - if cmd.IncludeReponseHeaders { + if cmd.IncludeResponseHeaders { headerBytes, _ := httputil.DumpResponse(httpResponse, false) bytesToWrite = append(bytesToWrite, headerBytes...) } diff --git a/command/v7/curl_command_test.go b/command/v7/curl_command_test.go index c76d76bc55a..440a5dc343c 100644 --- a/command/v7/curl_command_test.go +++ b/command/v7/curl_command_test.go @@ -26,13 +26,13 @@ var _ = Describe("curl Command", func() { fakeActor *v7fakes.FakeActor binaryName string - CustomHeaders []string - HTTPMethod string - HTTPData flag.PathWithAt - FailOnHTTPError bool - IncludeReponseHeaders bool - OutputFile flag.Path - executeErr error + CustomHeaders []string + HTTPMethod string + HTTPData flag.PathWithAt + FailOnHTTPError bool + IncludeResponseHeaders bool + OutputFile flag.Path + executeErr error ) BeforeEach(func() { @@ -49,13 +49,13 @@ var _ = Describe("curl Command", func() { SharedActor: fakeSharedActor, Actor: fakeActor, }, - RequiredArgs: flag.APIPath{Path: "/"}, - CustomHeaders: CustomHeaders, - HTTPMethod: HTTPMethod, - HTTPData: HTTPData, - FailOnHTTPError: FailOnHTTPError, - IncludeReponseHeaders: IncludeReponseHeaders, - OutputFile: OutputFile, + RequiredArgs: flag.APIPath{Path: "/"}, + CustomHeaders: CustomHeaders, + HTTPMethod: HTTPMethod, + HTTPData: HTTPData, + FailOnHTTPError: FailOnHTTPError, + IncludeResponseHeaders: IncludeResponseHeaders, + OutputFile: OutputFile, } binaryName = "faceman" @@ -128,7 +128,7 @@ var _ = Describe("curl Command", func() { When("the include-response-headers flag is set", func() { BeforeEach(func() { - cmd.IncludeReponseHeaders = true + cmd.IncludeResponseHeaders = true }) It("includes the headers in the output", func() { diff --git a/command/v7/delete_command_test.go b/command/v7/delete_command_test.go index 880f2629aa3..3118c9de29e 100644 --- a/command/v7/delete_command_test.go +++ b/command/v7/delete_command_test.go @@ -227,7 +227,7 @@ var _ = Describe("delete Command", func() { fakeActor.DeleteApplicationByNameAndSpaceReturns(v7action.Warnings{"some-warning"}, errors.New("some-error")) }) - It("displays all warnings, and returns the erorr", func() { + It("displays all warnings, and returns the error", func() { Expect(testUI.Err).To(Say("some-warning")) Expect(testUI.Out).To(Say(`Deleting app some-app in org some-org / space some-space as steve\.\.\.`)) Expect(testUI.Out).ToNot(Say("OK")) diff --git a/command/v7/delete_shared_domain_command_test.go b/command/v7/delete_shared_domain_command_test.go index 11bbfc3e846..a8fc4cd8eb9 100644 --- a/command/v7/delete_shared_domain_command_test.go +++ b/command/v7/delete_shared_domain_command_test.go @@ -212,7 +212,7 @@ var _ = Describe("delete-shared-domain Command", func() { fakeActor.DeleteDomainReturns(v7action.Warnings{"some-warning"}, errors.New("some-error")) }) - It("displays all warnings, and returns the erorr", func() { + It("displays all warnings, and returns the error", func() { Expect(testUI.Err).To(Say("some-warning")) Expect(testUI.Out).To(Say(`Deleting domain some-domain.com as steve\.\.\.`)) Expect(testUI.Out).ToNot(Say("OK")) diff --git a/command/v7/disable_feature_flag_command_test.go b/command/v7/disable_feature_flag_command_test.go index a5ec2ab340c..bf8c2f10137 100644 --- a/command/v7/disable_feature_flag_command_test.go +++ b/command/v7/disable_feature_flag_command_test.go @@ -96,7 +96,7 @@ var _ = Describe("Disable Feature Flag Command", func() { fakeActor.DisableFeatureFlagReturns(v7action.Warnings{"this is a warning"}, nil) }) - It("diaplays the feature flag was enabled", func() { + It("displays the feature flag was enabled", func() { featureFlagArgs := fakeActor.DisableFeatureFlagArgsForCall(0) Expect(featureFlagArgs).To(Equal(featureFlagName)) Expect(executeErr).NotTo(HaveOccurred()) diff --git a/command/v7/enable_feature_flag_command_test.go b/command/v7/enable_feature_flag_command_test.go index 84717d362a4..ae1a14f9676 100644 --- a/command/v7/enable_feature_flag_command_test.go +++ b/command/v7/enable_feature_flag_command_test.go @@ -96,7 +96,7 @@ var _ = Describe("Enable Feature Flag Command", func() { fakeActor.EnableFeatureFlagReturns(v7action.Warnings{"this is a warning"}, nil) }) - It("diaplays the feature flag was enabled", func() { + It("displays the feature flag was enabled", func() { featureFlagArgs := fakeActor.EnableFeatureFlagArgsForCall(0) Expect(featureFlagArgs).To(Equal(featureFlagName)) Expect(executeErr).NotTo(HaveOccurred()) diff --git a/command/v7/login_command_test.go b/command/v7/login_command_test.go index b2bcb502230..e49ffb52e3d 100644 --- a/command/v7/login_command_test.go +++ b/command/v7/login_command_test.go @@ -1380,7 +1380,7 @@ var _ = Describe("login Command", func() { fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "some-space"}) }) - It("displays that the spacce has been targeted", func() { + It("displays that the space has been targeted", func() { Expect(testUI.Out).To(Say(`space:\s+some-space`)) }) }) diff --git a/command/v7/shared/new_clients_test.go b/command/v7/shared/new_clients_test.go index 04bb1ec4b87..75a4049f7a7 100644 --- a/command/v7/shared/new_clients_test.go +++ b/command/v7/shared/new_clients_test.go @@ -57,7 +57,7 @@ var _ = Describe("New Clients", func() { }) }) - When("not targetting", func() { + When("not targeting", func() { It("does not target", func() { ccClient := NewWrappedCloudControllerClient(fakeConfig, testUI) Expect(ccClient).ToNot(BeNil()) diff --git a/command/v7/ssh_command_test.go b/command/v7/ssh_command_test.go index 492e0158220..25721f6c37c 100644 --- a/command/v7/ssh_command_test.go +++ b/command/v7/ssh_command_test.go @@ -203,14 +203,14 @@ var _ = Describe("ssh Command", func() { Entry("default - auto TTY", false, false, false, nil, sharedaction.RequestTTYAuto), Entry("disable tty - no TTY", true, false, false, nil, sharedaction.RequestTTYNo), Entry("force tty - forced TTY", false, true, false, nil, sharedaction.RequestTTYForce), - Entry("psudo tty - yes TTY", false, false, true, nil, sharedaction.RequestTTYYes), + Entry("pseudo tty - yes TTY", false, false, true, nil, sharedaction.RequestTTYYes), Entry("disable and force tty", true, true, false, translatableerror.ArgumentCombinationError{Args: []string{ "--disable-pseudo-tty", "-T", "--force-pseudo-tty", "--request-pseudo-tty", "-t", }}, sharedaction.TTYOption(0), ), - Entry("disable and requst tty", true, false, true, + Entry("disable and request tty", true, false, true, translatableerror.ArgumentCombinationError{Args: []string{ "--disable-pseudo-tty", "-T", "--force-pseudo-tty", "--request-pseudo-tty", "-t", }}, diff --git a/doc/adr/0004-v7-push-refactor.md b/doc/adr/0004-v7-push-refactor.md index 3fd517cc447..29cbe7b69bc 100644 --- a/doc/adr/0004-v7-push-refactor.md +++ b/doc/adr/0004-v7-push-refactor.md @@ -127,11 +127,11 @@ for _, changeAppFunc := range actor.ChangeApplicationSequence(plan) { } ``` -This is quite similar to the loop through `actor.PreparePushPlanSequence` above. We loop through `actor.ChangeApplicationSequence(plan)`, which returns an array of functions, and we call each one with the push plan. Each one returns a push plan that then gets passed in to the next function. +This is quite similar to the loop through `actor.PreparePushPlanSequence` above. We loop through `actor.ChangeApplicationSequence(plan)`, which returns an array of functions, and we call each one with the push plan. Each one returns a push plan that then gets passed into the next function. _Note: The rest of that code uses streams to report progress, errors, and warnings, but this is not the focus of this ADR (and we may end up changing this as well)._ -The **biggest difference** from `Conceputalize` is that instead of being a static list of functions (like `actor.PreparePushPlanSequence`), `actor.ChangeApplicationSequence` is a function that takes in a push plan and returns an array of `ChangeApplicationFunc`s. This allows us to dynamically build up the sequence of actions we run based on the push plan, rather than run the same sequence every time. +The **biggest difference** from `Conceptualize` is that instead of being a static list of functions (like `actor.PreparePushPlanSequence`), `actor.ChangeApplicationSequence` is a function that takes in a push plan and returns an array of `ChangeApplicationFunc`s. This allows us to dynamically build up the sequence of actions we run based on the push plan, rather than run the same sequence every time. Let's look at how that works: diff --git a/doc/adr/0007-integration-vs-command-test.md b/doc/adr/0007-integration-vs-command-test.md index 8d7a721741d..6de1052d9c3 100644 --- a/doc/adr/0007-integration-vs-command-test.md +++ b/doc/adr/0007-integration-vs-command-test.md @@ -121,7 +121,7 @@ When("an error is encountered getting the provided security group", func() { ## Consequences - Since this is not a very big change, we are not expecting to lose any - converage or increase run times. This is mostly for organization + coverage or increase run times. This is mostly for organization purposes. - There are no plans to retrofit existing tests to adhere to this ADR. diff --git a/doc/adr/0012-de-version-v8-code-base.md b/doc/adr/0012-de-version-v8-code-base.md index b27e23f9ab5..a3d725914ff 100644 --- a/doc/adr/0012-de-version-v8-code-base.md +++ b/doc/adr/0012-de-version-v8-code-base.md @@ -22,7 +22,7 @@ After [PR #2180](https://github.com/cloudfoundry/cli/pull/2180) we should be in * integration/v7 => integration/tests * Makefile ivi (integration versioned isolated) command => change to ii (integration isolated) * Makefile integration versioned global (ivg) => see above -* cf/ legacy directory => maybe rename it to something like legacy-cf, and put a README descring +* cf/ legacy directory => maybe rename it to something like legacy-cf, and put a README describing ## Decision diff --git a/fixtures/plugins/test_1.go b/fixtures/plugins/test_1.go index 3419bc7f91d..2d57bf235c5 100644 --- a/fixtures/plugins/test_1.go +++ b/fixtures/plugins/test_1.go @@ -95,7 +95,7 @@ func (c *Test1) GetMetadata() plugin.PluginMetadata { Alias: "test_1_cmd1_alias", HelpText: "help text for test_1_cmd1", UsageDetails: plugin.Usage{ - Usage: "Test plugin command\n cf test_1_cmd1 [-a] [-b] [--no-ouput]", + Usage: "Test plugin command\n cf test_1_cmd1 [-a] [-b] [--no-output]", Options: map[string]string{ "a": "flag to do nothing", "b": "another flag to do nothing", diff --git a/i18n/resources/i18n_resources.go b/i18n/resources/i18n_resources.go index 3ba2b2f077a..ac21975801a 100644 --- a/i18n/resources/i18n_resources.go +++ b/i18n/resources/i18n_resources.go @@ -281,8 +281,8 @@ func resourcesZhHantAllJson() (*asset, error) { // It returns an error if the asset could not be found or // could not be loaded. func Asset(name string) ([]byte, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { + canonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[canonicalName]; ok { a, err := f() if err != nil { return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) @@ -307,8 +307,8 @@ func MustAsset(name string) []byte { // It returns an error if the asset could not be found or // could not be loaded. func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { + canonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[canonicalName]; ok { a, err := f() if err != nil { return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) @@ -357,8 +357,8 @@ var _bindata = map[string]func() (*asset, error){ func AssetDir(name string) ([]string, error) { node := _bintree if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") + canonicalName := strings.Replace(name, "\\", "/", -1) + pathList := strings.Split(canonicalName, "/") for _, p := range pathList { node = node.Children[p] if node == nil { @@ -439,6 +439,6 @@ func RestoreAssets(dir, name string) error { } func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) + canonicalName := strings.Replace(name, "\\", "/", -1) + return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...) } diff --git a/integration/helpers/login.go b/integration/helpers/login.go index 07e28f81d2f..74445b19fbf 100644 --- a/integration/helpers/login.go +++ b/integration/helpers/login.go @@ -54,7 +54,7 @@ func GetAPI() string { return apiURL } -// LoginAs logs in to the CLI with 'cf auth' and the given username and password, +// LoginAs logs into the CLI with 'cf auth' and the given username and password, // retrying up to 3 times on failures. func LoginAs(username, password string) { env := map[string]string{ @@ -75,7 +75,7 @@ func LoginAs(username, password string) { Expect(session.ExitCode()).To(Equal(0)) } -// LoginCF logs in to the CLI using the username and password from the CF_INT_USERNAME +// LoginCF logs into the CLI using the username and password from the CF_INT_USERNAME // and CF_INT_PASSWORD environment variables, respectively, defaulting to "admin" for // each if either is not set. func LoginCF() string { @@ -87,7 +87,7 @@ func LoginCF() string { return username } -// LoginCFWithClientCredentials logs in to the CLI using client credentials from the CF_INT_CLIENT_ID and +// LoginCFWithClientCredentials logs into the CLI using client credentials from the CF_INT_CLIENT_ID and // CF_INT_CLIENT_SECRET environment variables and returns the client ID. If these environment variables // are not set, it skips the current test. func LoginCFWithClientCredentials() string { @@ -146,13 +146,13 @@ func TargetOrg(org string) { Eventually(CF("target", "-o", org)).Should(Exit(0)) } -// ClearTarget logs out and logs back in to the CLI using LogoutCF and LoginCF. +// ClearTarget logs out and logs back into the CLI using LogoutCF and LoginCF. func ClearTarget() { LogoutCF() LoginCF() } -// SetupCF logs in to the CLI with LoginCF, creates the given org and space, and targets that +// SetupCF logs into the CLI with LoginCF, creates the given org and space, and targets that // org and space. func SetupCF(org string, space string) { LoginCF() @@ -160,14 +160,14 @@ func SetupCF(org string, space string) { TargetOrgAndSpace(org, space) } -// SetupCFWithOrgOnly logs in to the CLI with LoginCF, creates the given org, and targets it. +// SetupCFWithOrgOnly logs into the CLI with LoginCF, creates the given org, and targets it. func SetupCFWithOrgOnly(org string) { LoginCF() CreateOrg(org) TargetOrg(org) } -// SetupCFWithGeneratedOrgAndSpaceNames logs in to the CLI with LoginCF, creates the org and +// SetupCFWithGeneratedOrgAndSpaceNames logs into the CLI with LoginCF, creates the org and // space with generated names, and targets that org and space. Returns the generated org so // that it can be deleted easily in cleanup step of the test. func SetupCFWithGeneratedOrgAndSpaceNames() string { diff --git a/integration/helpers/version.go b/integration/helpers/version.go index bf9dd585711..d5418d069b0 100644 --- a/integration/helpers/version.go +++ b/integration/helpers/version.go @@ -79,7 +79,7 @@ func SkipIfUAAVersionLessThan(version string) { } } -// SkipIfUAAVersionAtLeast is used to skip tests if the UAA varsion >= the specified version. +// SkipIfUAAVersionAtLeast is used to skip tests if the UAA version >= the specified version. func SkipIfUAAVersionAtLeast(version string) { if IsUAAVersionAtLeast(version) { Skip(fmt.Sprintf("Test requires UAA version less than %s", version)) @@ -96,10 +96,10 @@ func matchMajorAPIVersion(minVersion string) string { // GetAPIVersionV2 returns the V2 api version of the targeted API func GetAPIVersionV2() string { - return fetchAPIVersion().Links.CloudContollerV2.Meta.Version + return fetchAPIVersion().Links.CloudControllerV2.Meta.Version } -// SkipIfVersionLessThan is used to skip tests if the the API version < the specified version. If +// SkipIfVersionLessThan is used to skip tests if the API version < the specified version. If // minVersion contains the prefix 3 then the v3 version is checked, otherwise the v2 version is used. func SkipIfVersionLessThan(minVersion string) { if ignoreAPIVersion() { @@ -112,7 +112,7 @@ func SkipIfVersionLessThan(minVersion string) { } } -// SkipIfVersionLessThan is used to skip tests if the the API version >= the specified version. If +// SkipIfVersionLessThan is used to skip tests if the API version >= the specified version. If // maxVersion contains the prefix 3 then the v3 version is checked, otherwise the v2 version is used. func SkipIfVersionAtLeast(maxVersion string) { version := matchMajorAPIVersion(maxVersion) @@ -134,13 +134,13 @@ func ignoreAPIVersion() bool { type ccRoot struct { Links struct { - CloudContollerV2 struct { + CloudControllerV2 struct { Meta struct { Version string } } `json:"cloud_controller_v2"` - CloudContollerV3 struct { + CloudControllerV3 struct { Meta struct { Version string } @@ -172,7 +172,7 @@ func fetchAPIVersion() ccRoot { } func getAPIVersionV3() string { - return fetchAPIVersion().Links.CloudContollerV3.Meta.Version + return fetchAPIVersion().Links.CloudControllerV3.Meta.Version } // SkipIfNoRoutingAPI is used to skip tests if the routing API is not present diff --git a/integration/shared/isolated/internationalization_test.go b/integration/shared/isolated/internationalization_test.go index 260c061df23..ca55650c0d4 100644 --- a/integration/shared/isolated/internationalization_test.go +++ b/integration/shared/isolated/internationalization_test.go @@ -26,26 +26,26 @@ var _ = XDescribe("internationalization", func() { return helpers.CF("push", "--help") }), - Entry("when the the config and LANG environment variable is set, it uses config", func() *Session { + Entry("when the config and LANG environment variable is set, it uses config", func() *Session { session := helpers.CF("config", "--locale", "fr-FR") Eventually(session).Should(Exit(0)) return helpers.CFWithEnv(map[string]string{"LANG": "es-ES"}, "push", "--help") }), - Entry("when the the LANG environment variable is set", func() *Session { + Entry("when the LANG environment variable is set", func() *Session { return helpers.CFWithEnv(map[string]string{"LANG": "fr-FR"}, "push", "--help") }), - Entry("when the the LC_ALL environment variable is set", func() *Session { + Entry("when the LC_ALL environment variable is set", func() *Session { return helpers.CFWithEnv(map[string]string{"LC_ALL": "fr-FR"}, "push", "--help") }), - Entry("when the the LC_ALL and LANG environment variables are set, it uses LC_ALL", func() *Session { + Entry("when the LC_ALL and LANG environment variables are set, it uses LC_ALL", func() *Session { return helpers.CFWithEnv(map[string]string{"LC_ALL": "fr-FR", "LANG": "es-ES"}, "push", "--help") }), - Entry("when the the config, LC_ALL, and LANG is set, it uses config", func() *Session { + Entry("when the config, LC_ALL, and LANG is set, it uses config", func() *Session { session := helpers.CF("config", "--locale", "fr-FR") Eventually(session).Should(Exit(0)) @@ -60,15 +60,15 @@ var _ = XDescribe("internationalization", func() { Eventually(session).Should(Exit(0)) }, - Entry("when the the LANG and LC_ALL environment variable is not set", func() *Session { + Entry("when the LANG and LC_ALL environment variable is not set", func() *Session { return helpers.CF("push", "--help") }), - Entry("when the the LANG environment variable is set to a non-supported langauge", func() *Session { + Entry("when the LANG environment variable is set to a non-supported language", func() *Session { return helpers.CFWithEnv(map[string]string{"LANG": "jj-FF"}, "push", "--help") }), - Entry("when the the LC_ALL environment variable is set to a non-supported langauge", func() *Session { + Entry("when the LC_ALL environment variable is set to a non-supported language", func() *Session { return helpers.CFWithEnv(map[string]string{"LC_ALL": "jj-FF"}, "push", "--help") }), ) diff --git a/integration/v7/isolated/auth_command_test.go b/integration/v7/isolated/auth_command_test.go index e83633edb40..a8b675e627e 100644 --- a/integration/v7/isolated/auth_command_test.go +++ b/integration/v7/isolated/auth_command_test.go @@ -31,7 +31,7 @@ var _ = Describe("auth command", func() { Eventually(session).Should(Say("ENVIRONMENT VARIABLES:")) Eventually(session).Should(Say(`CF_USERNAME=user\s+Authenticating user. Overridden if USERNAME argument is provided.`)) - Eventually(session).Should(Say(`CF_PASSWORD=password\s+Password associated with user. Overriden if PASSWORD argument is provided.`)) + Eventually(session).Should(Say(`CF_PASSWORD=password\s+Password associated with user. Overridden if PASSWORD argument is provided.`)) Eventually(session).Should(Say("WARNING:")) Eventually(session).Should(Say("Providing your password as a command line option is highly discouraged")) @@ -276,7 +276,7 @@ var _ = Describe("auth command", func() { helpers.SkipIfUAAVersionAtLeast(uaaversion.MinUAAClientVersion) }) It("prints an error message", func() { - session := helpers.CF("auth", "some-username", "some-password", "--client-credentials", "--origin", "garbaje") + session := helpers.CF("auth", "some-username", "some-password", "--client-credentials", "--origin", "garbage") Eventually(session.Err).Should(Say("Option '--origin' requires UAA API version 4.19.0 or higher. Update your Cloud Foundry instance.")) Eventually(session).Should(Say("FAILED")) Eventually(session).Should(Exit(1)) @@ -289,7 +289,7 @@ var _ = Describe("auth command", func() { }) When("--client-credentials is also set", func() { It("displays the appropriate error message", func() { - session := helpers.CF("auth", "some-username", "some-password", "--client-credentials", "--origin", "garbaje") + session := helpers.CF("auth", "some-username", "some-password", "--client-credentials", "--origin", "garbage") Eventually(session.Err).Should(Say("Incorrect Usage: The following arguments cannot be used together: --client-credentials, --origin")) Eventually(session).Should(Exit(1)) diff --git a/integration/v7/isolated/create_private_domain_test.go b/integration/v7/isolated/create_private_domain_test.go index 5e24d16b4d3..d67dc246aba 100644 --- a/integration/v7/isolated/create_private_domain_test.go +++ b/integration/v7/isolated/create_private_domain_test.go @@ -100,7 +100,7 @@ var _ = Describe("create-private-domain command", func() { }) }) - When("pre-existing domain", func() { + When("preexisting domain", func() { var privateDomain1 helpers.Domain BeforeEach(func() { privateDomain1 = helpers.NewDomain(orgName, helpers.NewDomainName()) diff --git a/integration/v7/isolated/create_service_command_test.go b/integration/v7/isolated/create_service_command_test.go index 986fafe22a7..8d2973c24cb 100644 --- a/integration/v7/isolated/create_service_command_test.go +++ b/integration/v7/isolated/create_service_command_test.go @@ -356,7 +356,7 @@ var _ = Describe("create-service command", func() { }) It("displays an informative message and exits 1", func() { - session := helpers.CF("create-service", "foo", "bar", serviceInstanceName, "-c", filepath.Join(emptyDir, "non-existent-file")) + session := helpers.CF("create-service", "foo", "bar", serviceInstanceName, "-c", filepath.Join(emptyDir, "nonexistent-file")) Eventually(session.Err).Should(Say("Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object.")) Eventually(session).Should(Exit(1)) }) diff --git a/integration/v7/isolated/create_user_provided_service_command_test.go b/integration/v7/isolated/create_user_provided_service_command_test.go index 50253055cba..4a86b1f6174 100644 --- a/integration/v7/isolated/create_user_provided_service_command_test.go +++ b/integration/v7/isolated/create_user_provided_service_command_test.go @@ -67,7 +67,7 @@ var _ = Describe("create-user-provided-service command", func() { }) }) - When("an superflous argument is provided", func() { + When("an superfluous argument is provided", func() { It("fails and displays command usage", func() { session := helpers.CF("create-user-provided-service", "name", "extraparam") Eventually(session).Should(Exit(1)) @@ -94,7 +94,7 @@ var _ = Describe("create-user-provided-service command", func() { }) }) - When("targetting a space", func() { + When("targeting a space", func() { var ( userName string orgName string diff --git a/integration/v7/isolated/delete_command_test.go b/integration/v7/isolated/delete_command_test.go index 896ae58fb35..9d9e942dba1 100644 --- a/integration/v7/isolated/delete_command_test.go +++ b/integration/v7/isolated/delete_command_test.go @@ -94,7 +94,7 @@ var _ = Describe("delete command", func() { Expect(err).ToNot(HaveOccurred()) }) - It("shows more information when confiriming", func() { + It("shows more information when confirming", func() { username, _ := helpers.GetCredentials() session := helpers.CFWithStdin(buffer, "delete", "-r", appName) Eventually(session).Should(Say( diff --git a/integration/v7/isolated/delete_orphaned_routes_command_test.go b/integration/v7/isolated/delete_orphaned_routes_command_test.go index 6079739c767..e09b5c2911f 100644 --- a/integration/v7/isolated/delete_orphaned_routes_command_test.go +++ b/integration/v7/isolated/delete_orphaned_routes_command_test.go @@ -114,7 +114,7 @@ var _ = Describe("delete-orphaned-routes command", func() { }) }) - When("the user's inpiut is invalud", func() { + When("the user's input is invalid", func() { BeforeEach(func() { _, err := buffer.Write([]byte("abc\n")) Expect(err).ToNot(HaveOccurred()) diff --git a/integration/v7/isolated/delete_private_domain_command_test.go b/integration/v7/isolated/delete_private_domain_command_test.go index 36aa68854c6..1f17c1979f9 100644 --- a/integration/v7/isolated/delete_private_domain_command_test.go +++ b/integration/v7/isolated/delete_private_domain_command_test.go @@ -124,8 +124,8 @@ var _ = Describe("delete-private-domain command", func() { When("the domain doesn't exist", func() { It("displays OK and returns successfully", func() { - session := helpers.CFWithStdin(buffer, "delete-private-domain", "non-existent.com", "-f") - Eventually(session.Err).Should(Say(`Domain 'non-existent\.com' does not exist\.`)) + session := helpers.CFWithStdin(buffer, "delete-private-domain", "nonexistent.com", "-f") + Eventually(session.Err).Should(Say(`Domain 'nonexistent\.com' does not exist\.`)) Eventually(session).Should(Say("OK")) Eventually(session).Should(Exit(0)) }) diff --git a/integration/v7/isolated/delete_space_command_test.go b/integration/v7/isolated/delete_space_command_test.go index ef7a33caa86..9c6201426c1 100644 --- a/integration/v7/isolated/delete_space_command_test.go +++ b/integration/v7/isolated/delete_space_command_test.go @@ -194,7 +194,7 @@ var _ = Describe("delete-space command", func() { }) }) - When("the -o organzation does not exist", func() { + When("the -o organization does not exist", func() { BeforeEach(func() { helpers.LoginCF() }) diff --git a/integration/v7/isolated/delete_user_command_test.go b/integration/v7/isolated/delete_user_command_test.go index 6e4912632c9..d1632ad3544 100644 --- a/integration/v7/isolated/delete_user_command_test.go +++ b/integration/v7/isolated/delete_user_command_test.go @@ -106,8 +106,8 @@ var _ = Describe("delete-user command", func() { When("the user does not exist", func() { It("does not error but prints a message letting the user know it never existed", func() { - session := helpers.CF("delete-user", "non-existent-user", "-f") - Eventually(session).Should(Say("User 'non-existent-user' does not exist.")) + session := helpers.CF("delete-user", "nonexistent-user", "-f") + Eventually(session).Should(Say("User 'nonexistent-user' does not exist.")) Eventually(session).Should(Say("OK")) Eventually(session).Should(Exit(0)) }) diff --git a/integration/v7/isolated/events_command_test.go b/integration/v7/isolated/events_command_test.go index d8f7aafe8f6..7442cefaac5 100644 --- a/integration/v7/isolated/events_command_test.go +++ b/integration/v7/isolated/events_command_test.go @@ -75,7 +75,7 @@ var _ = Describe("events command", func() { It("displays events in the list", func() { - // Order of output is hard to assert here so we will just asseert we output only the events we expect and then rely on the unit + // Order of output is hard to assert here so we will just assert we output only the events we expect and then rely on the unit // tests to validate we are passing the `order_by=-created_at` query param to CAPI. The actual ordering is CAPIs concern. session := helpers.CF("events", appName) diff --git a/integration/v7/isolated/labels_command_test.go b/integration/v7/isolated/labels_command_test.go index 03d10e16c64..f2d45d7a2c0 100644 --- a/integration/v7/isolated/labels_command_test.go +++ b/integration/v7/isolated/labels_command_test.go @@ -111,9 +111,9 @@ var _ = Describe("labels command", func() { When("the app does not exist", func() { It("displays an error", func() { - session := helpers.CF("labels", "app", "non-existent-app") - Eventually(session).Should(Say(regexp.QuoteMeta("Getting labels for app non-existent-app in org %s / space %s as %s...\n"), orgName, spaceName, username)) - Eventually(session.Err).Should(Say("App 'non-existent-app' not found")) + session := helpers.CF("labels", "app", "nonexistent-app") + Eventually(session).Should(Say(regexp.QuoteMeta("Getting labels for app nonexistent-app in org %s / space %s as %s...\n"), orgName, spaceName, username)) + Eventually(session.Err).Should(Say("App 'nonexistent-app' not found")) Eventually(session).Should(Say("FAILED")) Eventually(session).Should(Exit(1)) }) @@ -135,7 +135,7 @@ var _ = Describe("labels command", func() { Eventually(session).Should(Exit(0)) }) - It("fails if a non-existent stack is specified", func() { + It("fails if a nonexistent stack is specified", func() { session := helpers.CF("labels", "buildpack", buildpackName, "-s", "bogus-stack") Eventually(session.Err).Should(Say("Buildpack '%s' with stack 'bogus-stack' not found", buildpackName)) Eventually(session).Should(Say("FAILED")) @@ -211,7 +211,7 @@ var _ = Describe("labels command", func() { Eventually(session).Should(Exit(0)) }) - It("fails if a non-existent stack is specified", func() { + It("fails if a nonexistent stack is specified", func() { session := helpers.CF("labels", "buildpack", buildpackName, "-s", "bogus-stack") Eventually(session.Err).Should(Say("Buildpack '%s' with stack 'bogus-stack' not found", buildpackName)) Eventually(session).Should(Say("FAILED")) @@ -259,7 +259,7 @@ var _ = Describe("labels command", func() { Eventually(session).Should(Exit(1)) }) - It("fails when a non-existent stack is given", func() { + It("fails when a nonexistent stack is given", func() { session := helpers.CF("labels", "buildpack", buildpackName, "-s", "bogus-stack") Eventually(session.Err).Should(Say("Buildpack '%s' with stack 'bogus-stack' not found", buildpackName)) Eventually(session).Should(Say("FAILED")) @@ -306,7 +306,7 @@ var _ = Describe("labels command", func() { Eventually(session).Should(Exit(0)) }) - It("fails if a non-existent stack is specified", func() { + It("fails if a nonexistent stack is specified", func() { session := helpers.CF("labels", "buildpack", buildpackName, "-s", "bogus-stack") Eventually(session.Err).Should(Say("Buildpack '%s' with stack 'bogus-stack' not found", buildpackName)) Eventually(session).Should(Say("FAILED")) @@ -363,10 +363,10 @@ var _ = Describe("labels command", func() { When("the domain does not exist", func() { It("displays an error", func() { - session := helpers.CF("labels", "domain", "non-existent-domain") + session := helpers.CF("labels", "domain", "nonexistent-domain") Eventually(session).Should(Exit(1)) - Expect(session).To(Say(regexp.QuoteMeta("Getting labels for domain non-existent-domain as %s...\n\n"), username)) - Expect(session.Err).To(Say("Domain 'non-existent-domain' not found")) + Expect(session).To(Say(regexp.QuoteMeta("Getting labels for domain nonexistent-domain as %s...\n\n"), username)) + Expect(session.Err).To(Say("Domain 'nonexistent-domain' not found")) Expect(session).To(Say("FAILED")) }) }) @@ -407,9 +407,9 @@ var _ = Describe("labels command", func() { When("the org does not exist", func() { It("displays an error", func() { - session := helpers.CF("labels", "org", "non-existent-org") - Eventually(session).Should(Say(regexp.QuoteMeta("Getting labels for org %s as %s...\n\n"), "non-existent-org", username)) - Eventually(session.Err).Should(Say("Organization 'non-existent-org' not found")) + session := helpers.CF("labels", "org", "nonexistent-org") + Eventually(session).Should(Say(regexp.QuoteMeta("Getting labels for org %s as %s...\n\n"), "nonexistent-org", username)) + Eventually(session.Err).Should(Say("Organization 'nonexistent-org' not found")) Eventually(session).Should(Say("FAILED")) Eventually(session).Should(Exit(1)) }) @@ -469,9 +469,9 @@ var _ = Describe("labels command", func() { When("the route does not exist", func() { It("displays an error", func() { - session := helpers.CF("labels", "route", "non-existent-route.example.com") + session := helpers.CF("labels", "route", "nonexistent-route.example.com") Eventually(session).Should(Exit(1)) - Expect(session).Should(Say(regexp.QuoteMeta("Getting labels for route non-existent-route.example.com in org %s / space %s as %s...\n"), orgName, spaceName, username)) + Expect(session).Should(Say(regexp.QuoteMeta("Getting labels for route nonexistent-route.example.com in org %s / space %s as %s...\n"), orgName, spaceName, username)) Expect(session.Err).To(Say("Domain 'example.com' not found")) Expect(session).To(Say("FAILED")) }) @@ -522,9 +522,9 @@ var _ = Describe("labels command", func() { When("the service broker does not exist", func() { It("displays an error", func() { - session := helpers.CF("labels", "service-broker", "non-existent-broker") - Eventually(session).Should(Say(regexp.QuoteMeta("Getting labels for service-broker %s as %s...\n\n"), "non-existent-broker", username)) - Eventually(session.Err).Should(Say("Service broker 'non-existent-broker' not found")) + session := helpers.CF("labels", "service-broker", "nonexistent-broker") + Eventually(session).Should(Say(regexp.QuoteMeta("Getting labels for service-broker %s as %s...\n\n"), "nonexistent-broker", username)) + Eventually(session.Err).Should(Say("Service broker 'nonexistent-broker' not found")) Eventually(session).Should(Say("FAILED")) Eventually(session).Should(Exit(1)) }) @@ -574,9 +574,9 @@ var _ = Describe("labels command", func() { When("does not exist", func() { It("displays an error", func() { - session := helpers.CF("labels", "service-instance", "non-existent-app") - Eventually(session).Should(Say(regexp.QuoteMeta("Getting labels for service-instance non-existent-app in org %s / space %s as %s...\n"), orgName, spaceName, username)) - Eventually(session.Err).Should(Say("Service instance 'non-existent-app' not found")) + session := helpers.CF("labels", "service-instance", "nonexistent-app") + Eventually(session).Should(Say(regexp.QuoteMeta("Getting labels for service-instance nonexistent-app in org %s / space %s as %s...\n"), orgName, spaceName, username)) + Eventually(session.Err).Should(Say("Service instance 'nonexistent-app' not found")) Eventually(session).Should(Say("FAILED")) Eventually(session).Should(Exit(1)) }) @@ -641,9 +641,9 @@ var _ = Describe("labels command", func() { When("the service offering does not exist", func() { It("displays an error", func() { - session := helpers.CF("labels", "service-offering", "non-existent-offering") - Eventually(session).Should(Say(regexp.QuoteMeta("Getting labels for service-offering non-existent-offering as %s...\n"), username)) - Eventually(session.Err).Should(Say("Service offering 'non-existent-offering' not found")) + session := helpers.CF("labels", "service-offering", "nonexistent-offering") + Eventually(session).Should(Say(regexp.QuoteMeta("Getting labels for service-offering nonexistent-offering as %s...\n"), username)) + Eventually(session.Err).Should(Say("Service offering 'nonexistent-offering' not found")) Eventually(session).Should(Say("FAILED")) Eventually(session).Should(Exit(1)) }) @@ -709,9 +709,9 @@ var _ = Describe("labels command", func() { When("the service plan does not exist", func() { It("displays an error", func() { - session := helpers.CF("labels", "service-plan", "non-existent-plan") - Eventually(session).Should(Say(regexp.QuoteMeta("Getting labels for service-plan non-existent-plan as %s...\n"), username)) - Eventually(session.Err).Should(Say("Service plan 'non-existent-plan' not found")) + session := helpers.CF("labels", "service-plan", "nonexistent-plan") + Eventually(session).Should(Say(regexp.QuoteMeta("Getting labels for service-plan nonexistent-plan as %s...\n"), username)) + Eventually(session.Err).Should(Say("Service plan 'nonexistent-plan' not found")) Eventually(session).Should(Say("FAILED")) Eventually(session).Should(Exit(1)) }) @@ -758,9 +758,9 @@ var _ = Describe("labels command", func() { When("the stack does not exist", func() { It("displays an error", func() { - session := helpers.CF("labels", "stack", "non-existent-stack") - Eventually(session).Should(Say(regexp.QuoteMeta("Getting labels for stack %s as %s...\n\n"), "non-existent-stack", username)) - Eventually(session.Err).Should(Say("Stack 'non-existent-stack' not found")) + session := helpers.CF("labels", "stack", "nonexistent-stack") + Eventually(session).Should(Say(regexp.QuoteMeta("Getting labels for stack %s as %s...\n\n"), "nonexistent-stack", username)) + Eventually(session.Err).Should(Say("Stack 'nonexistent-stack' not found")) Eventually(session).Should(Say("FAILED")) Eventually(session).Should(Exit(1)) }) @@ -803,9 +803,9 @@ var _ = Describe("labels command", func() { When("the space does not exist", func() { It("displays an error", func() { - session := helpers.CF("labels", "space", "non-existent-space") - Eventually(session).Should(Say(regexp.QuoteMeta("Getting labels for space %s in org %s as %s...\n"), "non-existent-space", orgName, username)) - Eventually(session.Err).Should(Say("Space 'non-existent-space' not found")) + session := helpers.CF("labels", "space", "nonexistent-space") + Eventually(session).Should(Say(regexp.QuoteMeta("Getting labels for space %s in org %s as %s...\n"), "nonexistent-space", orgName, username)) + Eventually(session.Err).Should(Say("Space 'nonexistent-space' not found")) Eventually(session).Should(Say("FAILED")) Eventually(session).Should(Exit(1)) }) diff --git a/integration/v7/isolated/login_command_test.go b/integration/v7/isolated/login_command_test.go index 70004c90b57..a4c5d0227e4 100644 --- a/integration/v7/isolated/login_command_test.go +++ b/integration/v7/isolated/login_command_test.go @@ -223,7 +223,7 @@ var _ = Describe("login command", func() { }) When("the API endpoint's scheme is https", func() { - // This test is somewhat redundant because the integration test setup will have alreayd logged in successfully with certificates at this point + // This test is somewhat redundant because the integration test setup will have already logged in successfully with certificates at this point // In the interest of test coverage however, we have decided to keep it in. When("the OS provides a valid SSL Certificate (Unix: SSL_CERT_FILE or SSL_CERT_DIR Environment variables) (Windows: Import-Certificate call)", func() { BeforeEach(func() { @@ -753,7 +753,7 @@ var _ = Describe("login command", func() { }) When("user does not select an organization", func() { - It("succesfully logs in but does not target any org", func() { + It("successfully logs in but does not target any org", func() { input := NewBuffer() _, err := input.Write([]byte("\n")) Expect(err).ToNot(HaveOccurred()) diff --git a/integration/v7/isolated/network_policies_command_test.go b/integration/v7/isolated/network_policies_command_test.go index 22fdba973dc..2181839bdba 100644 --- a/integration/v7/isolated/network_policies_command_test.go +++ b/integration/v7/isolated/network_policies_command_test.go @@ -175,7 +175,7 @@ var _ = Describe("network-policies command", func() { }) }) - When("policies are filtered by a non-existent source app", func() { + When("policies are filtered by a nonexistent source app", func() { It("returns an error", func() { session := helpers.CF("network-policies", "--source", "pineapple") diff --git a/integration/v7/isolated/oauth_token_command_test.go b/integration/v7/isolated/oauth_token_command_test.go index 38490c5322e..148e5f5df38 100644 --- a/integration/v7/isolated/oauth_token_command_test.go +++ b/integration/v7/isolated/oauth_token_command_test.go @@ -93,7 +93,7 @@ var _ = Describe("oauth-token command", func() { When("the oauth client ID and secret combination is invalid", func() { BeforeEach(func() { helpers.SetConfig(func(conf *configv3.Config) { - conf.ConfigFile.UAAOAuthClient = "non-existent-client" + conf.ConfigFile.UAAOAuthClient = "nonexistent-client" conf.ConfigFile.UAAOAuthClientSecret = "some-secret" }) }) @@ -151,7 +151,7 @@ var _ = Describe("oauth-token command", func() { When("the oauth client ID and secret combination is invalid", func() { BeforeEach(func() { helpers.SetConfig(func(conf *configv3.Config) { - conf.ConfigFile.UAAOAuthClient = "non-existent-client" + conf.ConfigFile.UAAOAuthClient = "nonexistent-client" conf.ConfigFile.UAAOAuthClientSecret = "some-secret" }) }) diff --git a/integration/v7/isolated/restage_command_test.go b/integration/v7/isolated/restage_command_test.go index eee7355cb49..1306df7d2bd 100644 --- a/integration/v7/isolated/restage_command_test.go +++ b/integration/v7/isolated/restage_command_test.go @@ -116,7 +116,7 @@ var _ = Describe("restage command", func() { session := helpers.CF("restage", appName) Eventually(session).Should(Say(`Restaging app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) - // The staticfile_buildback does compile an index.html file. However, it requires a "Staticfile" during buildpack detection. + // The staticfile_buildpack does compile an index.html file. However, it requires a "Staticfile" during buildpack detection. Eventually(session.Err).Should(Say("Error staging application: NoAppDetectedError - An app was not successfully detected by any available buildpack")) Eventually(session.Err).Should(Say(`TIP: Use 'cf buildpacks' to see a list of supported buildpacks.`)) Eventually(session).Should(Exit(1)) diff --git a/integration/v7/isolated/revisions_command_test.go b/integration/v7/isolated/revisions_command_test.go index ee014778750..8795bdb7479 100644 --- a/integration/v7/isolated/revisions_command_test.go +++ b/integration/v7/isolated/revisions_command_test.go @@ -49,7 +49,7 @@ var _ = Describe("revisions command", func() { }) }) - When("targetting and org and space", func() { + When("targeting and org and space", func() { BeforeEach(func() { helpers.SetupCF(orgName, spaceName) }) diff --git a/integration/v7/isolated/service_access_command_test.go b/integration/v7/isolated/service_access_command_test.go index 43384585d35..b69614a9b05 100644 --- a/integration/v7/isolated/service_access_command_test.go +++ b/integration/v7/isolated/service_access_command_test.go @@ -49,28 +49,28 @@ var _ = Describe("service-access command", func() { When("-b is provided with a broker name that does not exist", func() { It("shows an error message", func() { - session := helpers.CF("service-access", "-b", "non-existent-broker") + session := helpers.CF("service-access", "-b", "nonexistent-broker") Eventually(session).Should(Exit(1)) - Expect(session).To(Say(`Getting service access for broker non-existent-broker as %s\.\.\.`, userName)) - Expect(session.Err).To(Say(`(Service broker 'non-existent-broker' not found|No service offerings found for service broker 'non-existent-broker')\.`)) + Expect(session).To(Say(`Getting service access for broker nonexistent-broker as %s\.\.\.`, userName)) + Expect(session.Err).To(Say(`(Service broker 'nonexistent-broker' not found|No service offerings found for service broker 'nonexistent-broker')\.`)) }) }) When("-e is provided with a service name that does not exist", func() { It("shows an error message", func() { - session := helpers.CF("service-access", "-e", "non-existent-service") + session := helpers.CF("service-access", "-e", "nonexistent-service") Eventually(session).Should(Exit(1)) - Expect(session).To(Say(`Getting service access for service offering non-existent-service as %s\.\.\.`, userName)) - Expect(session.Err).To(Say(`Service offering 'non-existent-service' not found\.`)) + Expect(session).To(Say(`Getting service access for service offering nonexistent-service as %s\.\.\.`, userName)) + Expect(session.Err).To(Say(`Service offering 'nonexistent-service' not found\.`)) }) }) When("-o is provided with a org name that does not exist", func() { It("shows an error message", func() { - session := helpers.CF("service-access", "-o", "non-existent-org") + session := helpers.CF("service-access", "-o", "nonexistent-org") Eventually(session).Should(Exit(1)) - Expect(session).To(Say(`Getting service access for organization non-existent-org as %s\.\.\.`, userName)) - Expect(session.Err).To(Say(`Organization 'non-existent-org' not found`)) + Expect(session).To(Say(`Getting service access for organization nonexistent-org as %s\.\.\.`, userName)) + Expect(session.Err).To(Say(`Organization 'nonexistent-org' not found`)) }) }) diff --git a/integration/v7/isolated/set_label_command_test.go b/integration/v7/isolated/set_label_command_test.go index 40091753876..fcd7a321cd0 100644 --- a/integration/v7/isolated/set_label_command_test.go +++ b/integration/v7/isolated/set_label_command_test.go @@ -68,7 +68,7 @@ var _ = Describe("set-label command", func() { testExpectedBehaviors := func(resourceType, resourceTypeFormatted, resourceName string) { By("checking the behavior when the resource does not exist", func() { - unknownResourceName := "non-existent-" + resourceType + unknownResourceName := "nonexistent-" + resourceType session := helpers.CF("set-label", resourceType, unknownResourceName, "some-key=some-value") Eventually(session.Err).Should(Say("%s '%s' not found", resourceTypeFormatted, unknownResourceName)) Eventually(session).Should(Say("FAILED")) @@ -331,9 +331,9 @@ var _ = Describe("set-label command", func() { When("the route is unknown", func() { It("displays an error", func() { - invalidRoute := "non-existent-host." + domainName + invalidRoute := "nonexistent-host." + domainName session := helpers.CF("set-label", "route", invalidRoute, "some-key=some-value") - Eventually(session.Err).Should(Say(`Route with host 'non-existent-host', domain '%s', and path '/' not found\.`, domainName)) + Eventually(session.Err).Should(Say(`Route with host 'nonexistent-host', domain '%s', and path '/' not found\.`, domainName)) Eventually(session.Out).Should(Say("FAILED")) Eventually(session).Should(Exit(1)) }) @@ -510,7 +510,7 @@ var _ = Describe("set-label command", func() { }) }) - When("a non-existent stack is specified", func() { + When("a nonexistent stack is specified", func() { It("displays an error", func() { bogusStackName := stacks[0] + "-bogus-" + stacks[1] session := helpers.CF("set-label", "buildpack", buildpackName, "olive=3", "mangosteen=4", "--stack", bogusStackName) @@ -575,7 +575,7 @@ var _ = Describe("set-label command", func() { }) }) - When("a non-existent stack is specified", func() { + When("a nonexistent stack is specified", func() { It("displays an error", func() { bogusStackName := stacks[0] + "-bogus-" + stacks[1] session := helpers.CF("set-label", "buildpack", buildpackName, "olive=3", "mangosteen=4", "--stack", bogusStackName) diff --git a/integration/v7/isolated/share_route_command_test.go b/integration/v7/isolated/share_route_command_test.go index 68cbc538bcb..c1a646982a2 100644 --- a/integration/v7/isolated/share_route_command_test.go +++ b/integration/v7/isolated/share_route_command_test.go @@ -56,7 +56,7 @@ var _ = Describe("share route command", func() { }) }) - When("the environment is set up conrrectly", func() { + When("the environment is set up correctly", func() { var ( userName string orgName string @@ -76,7 +76,7 @@ var _ = Describe("share route command", func() { helpers.QuickDeleteOrg(orgName) }) - When("the domain extists", func() { + When("the domain exists", func() { var ( domainName string targetSpaceName string diff --git a/integration/v7/isolated/space_ssh_allowed_command_test.go b/integration/v7/isolated/space_ssh_allowed_command_test.go index a115fa64834..b6203ef9610 100644 --- a/integration/v7/isolated/space_ssh_allowed_command_test.go +++ b/integration/v7/isolated/space_ssh_allowed_command_test.go @@ -65,7 +65,7 @@ var _ = Describe("space-ssh-allowed command", func() { When("the space does not exist", func() { BeforeEach(func() { - spaceName = "non-existent-space" + spaceName = "nonexistent-space" }) It("displays a missing space error message and fails", func() { diff --git a/integration/v7/isolated/unset_label_command_test.go b/integration/v7/isolated/unset_label_command_test.go index c63edc1a945..813312b170a 100644 --- a/integration/v7/isolated/unset_label_command_test.go +++ b/integration/v7/isolated/unset_label_command_test.go @@ -139,9 +139,9 @@ var _ = Describe("unset-label command", func() { When("the buildpack is unknown", func() { It("displays an error", func() { - session := helpers.CF("unset-label", "buildpack", "non-existent-buildpack", "some-key=some-value") + session := helpers.CF("unset-label", "buildpack", "nonexistent-buildpack", "some-key=some-value") Eventually(session).Should(Exit(1)) - Expect(session.Err).Should(Say("Buildpack 'non-existent-buildpack' not found")) + Expect(session.Err).Should(Say("Buildpack 'nonexistent-buildpack' not found")) Expect(session).Should(Say("FAILED")) }) }) diff --git a/integration/v7/isolated/update_user_provided_service_command_test.go b/integration/v7/isolated/update_user_provided_service_command_test.go index 2556ceb3895..833ed47bffc 100644 --- a/integration/v7/isolated/update_user_provided_service_command_test.go +++ b/integration/v7/isolated/update_user_provided_service_command_test.go @@ -108,10 +108,10 @@ var _ = Describe("update-user-provided-service command", func() { When("the user-provided service instance does not exist", func() { It("displays an informative error and exits 1", func() { - session := helpers.CF("update-user-provided-service", "non-existent-service", "-l", "syslog://example.com") + session := helpers.CF("update-user-provided-service", "nonexistent-service", "-l", "syslog://example.com") Eventually(session).Should(Exit(1)) - Expect(session.Err).To(Say("Service instance 'non-existent-service' not found")) + Expect(session.Err).To(Say("Service instance 'nonexistent-service' not found")) Expect(session.Out).To(Say("FAILED")) }) }) diff --git a/plugin/plugin_examples/basic_plugin.go b/plugin/plugin_examples/basic_plugin.go index f3d7f90d76a..b3662d08644 100644 --- a/plugin/plugin_examples/basic_plugin.go +++ b/plugin/plugin_examples/basic_plugin.go @@ -15,7 +15,7 @@ type BasicPlugin struct{} // // Run(....) is the entry point when the core CLI is invoking a command defined // by a plugin. The first parameter, plugin.CliConnection, is a struct that can -// be used to invoke cli commands. The second paramter, args, is a slice of +// be used to invoke cli commands. The second parameter, args, is a slice of // strings. args[0] will be the name of the command, and will be followed by // any additional arguments a cli user typed in. // @@ -35,7 +35,7 @@ func (c *BasicPlugin) Run(cliConnection plugin.CliConnection, args []string) { // GetMetadata() returns a PluginMetadata struct. The first field, Name, // determines the name of the plugin which should generally be without spaces. // If there are spaces in the name a user will need to properly quote the name -// during uninstall otherwise the name will be treated as seperate arguments. +// during uninstall otherwise the name will be treated as separate arguments. // The second value is a slice of Command structs. Our slice only contains one // Command Struct, but could contain any number of them. The first field Name // defines the command `cf basic-plugin-command` once installed into the CLI. The diff --git a/plugin/plugin_examples/echo.go b/plugin/plugin_examples/echo.go index 770cc8db807..3a0e8f46215 100644 --- a/plugin/plugin_examples/echo.go +++ b/plugin/plugin_examples/echo.go @@ -25,7 +25,7 @@ func main() { func (pluginDemo *PluginDemonstratingParams) Run(cliConnection plugin.CliConnection, args []string) { // Initialize flags echoFlagSet := flag.NewFlagSet("echo", flag.ExitOnError) - uppercase := echoFlagSet.Bool("uppercase", false, "displayes all provided text in uppercase") + uppercase := echoFlagSet.Bool("uppercase", false, "displayed all provided text in uppercase") // Parse starting from [1] because the [0]th element is the // name of the command diff --git a/resources/droplet_resource.go b/resources/droplet_resource.go index 515bfc61133..27dc2574f3f 100644 --- a/resources/droplet_resource.go +++ b/resources/droplet_resource.go @@ -28,7 +28,7 @@ type Droplet struct { type DropletBuildpack struct { // Name is the buildpack name. Name string `json:"name"` - // BuildpackName is the the name reported by the buildpack. + // BuildpackName is the name reported by the buildpack. BuildpackName string `json:"buildpack_name"` // DetectOutput is the output of the buildpack detect script. DetectOutput string `json:"detect_output"` diff --git a/util/clissh/ssh_test.go b/util/clissh/ssh_test.go index 58f4d2d744c..4a75c7be39c 100644 --- a/util/clissh/ssh_test.go +++ b/util/clissh/ssh_test.go @@ -478,7 +478,7 @@ var _ = Describe("CLI SSH", func() { Expect(fakeSecureSession.ShellCallCount()).To(Equal(1)) }) - It("does not not restore the terminal", func() { + It("does not restore the terminal", func() { Expect(fakeSecureSession.ShellCallCount()).To(Equal(1)) Expect(fakeTerminalHelper.SetRawTerminalCallCount()).To(Equal(1)) Expect(fakeTerminalHelper.RestoreTerminalCallCount()).To(Equal(0)) @@ -578,7 +578,7 @@ var _ = Describe("CLI SSH", func() { }) }) - When("a command is specifed", func() { + When("a command is specified", func() { BeforeEach(func() { commands = []string{"echo", "-n", "hello"} }) diff --git a/util/configv3/plugins_config_test.go b/util/configv3/plugins_config_test.go index 58e92819a29..d537db68fbf 100644 --- a/util/configv3/plugins_config_test.go +++ b/util/configv3/plugins_config_test.go @@ -308,7 +308,7 @@ var _ = Describe("PluginsConfig", func() { setPluginConfig(pluginsPath, rawConfig) }) - It("returns the pluging sorted by name", func() { + It("returns the plugins sorted by name", func() { config, err := LoadConfig() Expect(err).ToNot(HaveOccurred()) Expect(config.Plugins()).To(Equal([]Plugin{ diff --git a/util/manifest/application.go b/util/manifest/application.go index e539a719028..b748c1753f0 100644 --- a/util/manifest/application.go +++ b/util/manifest/application.go @@ -150,7 +150,7 @@ func (app *Application) UnmarshalYAML(unmarshaller func(interface{}) error) erro } // "null" values are identical to non-existant values in YAML. In order to - // detect if an explicit null is given, a manual existance check is required. + // detect if an explicit null is given, a manual existence check is required. exists := map[string]interface{}{} err = unmarshaller(&exists) if err != nil { diff --git a/util/manifestparser/application.go b/util/manifestparser/application.go index 4eae68b1ecc..3b12942dfcc 100644 --- a/util/manifestparser/application.go +++ b/util/manifestparser/application.go @@ -61,7 +61,7 @@ func (application *Application) SetStartCommand(command string) { func (application *Application) UnmarshalYAML(unmarshal func(v interface{}) error) error { // This prevents infinite recursion. The alias type does not implement the unmarshaller interface - // so by casting application to a alias pointer, it will unmarshal in to the same memory without calling + // so by casting application to a alias pointer, it will unmarshal into the same memory without calling // UnmarshalYAML on itself infinite times type Alias Application aliasPntr := (*Alias)(application) diff --git a/util/manifestparser/application_test.go b/util/manifestparser/application_test.go index d39eb28db8a..fb8b8ce9ac7 100644 --- a/util/manifestparser/application_test.go +++ b/util/manifestparser/application_test.go @@ -485,7 +485,7 @@ log-rate-limit-per-second: 5K app.RemainingManifestFields = map[string]interface{}{} }) - It("sets the buildpackks in the map", func() { + It("sets the buildpacks in the map", func() { Expect(app.RemainingManifestFields["buildpacks"]).To(ConsistOf("bp1", "bp2")) }) diff --git a/util/manifestparser/process.go b/util/manifestparser/process.go index 6481225a6af..07d2c35bc54 100644 --- a/util/manifestparser/process.go +++ b/util/manifestparser/process.go @@ -34,7 +34,7 @@ func (process *Process) SetStartCommand(command string) { func (process *Process) UnmarshalYAML(unmarshal func(v interface{}) error) error { // This prevents infinite recursion. The Alias type does not implement the unmarshaller interface - // so by casting application to a alias pointer, it will unmarshal in to the same memory without calling + // so by casting application to a alias pointer, it will unmarshal into the same memory without calling // UnmarshalYAML on itself infinite times type Alias Process aliasPntr := (*Alias)(process) diff --git a/util/randomword/generator.go b/util/randomword/generator.go index 06eba5f22ab..d7c97a5ba6c 100644 --- a/util/randomword/generator.go +++ b/util/randomword/generator.go @@ -83,7 +83,7 @@ wacky wise zany` -const nouns = `ardvark +const nouns = `aardvark alligator antelope baboon @@ -170,7 +170,7 @@ rabbit ratel raven reedbuck -rhinocerous +rhinoceros roan sable serval diff --git a/util/ui/i18n.go b/util/ui/i18n.go index 38b5c101f37..559a0e6db22 100644 --- a/util/ui/i18n.go +++ b/util/ui/i18n.go @@ -63,7 +63,7 @@ func GetTranslationFunc(reader LocaleReader) (TranslateFunc, error) { } // ParseLocale will return a locale formatted as "-" for all non-Chinese lanagues. For Chinese, it will return +// code>" for all non-Chinese languages. For Chinese, it will return // "zh-