diff --git a/go.mod b/go.mod index 7d88fa3d2..f9ca8b07c 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,6 @@ require ( github.com/hashicorp/go-memdb v1.3.4 github.com/hashicorp/go-multierror v1.1.1 github.com/incubator4/go-resty-expr v0.1.1 - github.com/onsi/ginkgo v1.16.4 github.com/onsi/ginkgo/v2 v2.20.0 github.com/onsi/gomega v1.34.1 github.com/pkg/errors v0.9.1 @@ -116,6 +115,7 @@ require ( github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-uuid v1.0.1 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/hpcloud/tail v1.0.0 // indirect github.com/huandu/xstrings v1.4.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/imkira/go-interpol v1.1.0 // indirect @@ -151,7 +151,6 @@ require ( github.com/moul/http2curl v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect - github.com/nxadm/tail v1.4.11 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect @@ -209,6 +208,7 @@ require ( google.golang.org/grpc v1.65.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + gopkg.in/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 29cbfeb57..7e00a963b 100644 --- a/go.sum +++ b/go.sum @@ -145,9 +145,6 @@ github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6 github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -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.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= @@ -187,7 +184,6 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= @@ -216,7 +212,6 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU 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.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= @@ -288,6 +283,7 @@ github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iP github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f h1:7LYC+Yfkj3CTRcShK0KOL/w6iTiKyqqBA9a41Wnggw8= github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= @@ -410,18 +406,10 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= -github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -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 v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo/v2 v2.20.0 h1:PE84V2mHqoT1sglvHc8ZdQtPcwmvvt29WLEEO3xmdZw= github.com/onsi/ginkgo/v2 v2.20.0/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -626,7 +614,6 @@ golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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-20181114220301-adae6a3d119a/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= @@ -634,7 +621,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn 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-20200226121028-0de0cce0169b/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-20201021035429-f5854403a974/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-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -658,21 +644,15 @@ golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190222072716-a9d3bda3a223/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-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/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-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-20200323222414-85ca7c5b95cd/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= 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-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -684,7 +664,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -715,7 +694,6 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -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.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= @@ -746,7 +724,6 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ 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.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= @@ -762,6 +739,7 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= @@ -769,7 +747,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep 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/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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= diff --git a/internal/controller/gateway_controller.go b/internal/controller/gateway_controller.go index b87fe7820..d62ff4fd1 100644 --- a/internal/controller/gateway_controller.go +++ b/internal/controller/gateway_controller.go @@ -6,8 +6,13 @@ import ( "reflect" "github.com/api7/api7-ingress-controller/internal/controller/config" + "github.com/api7/api7-ingress-controller/internal/controlplane" + "github.com/api7/api7-ingress-controller/internal/controlplane/translator" + "github.com/api7/gopkg/pkg/log" "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" @@ -23,9 +28,9 @@ import ( // GatewayReconciler reconciles a Gateway object. type GatewayReconciler struct { //nolint:revive client.Client - Scheme *runtime.Scheme - - Log logr.Logger + Scheme *runtime.Scheme + ControlPlaneClient controlplane.Controlplane + Log logr.Logger } // SetupWithManager sets up the controller with the Manager. @@ -47,9 +52,17 @@ func (r *GatewayReconciler) SetupWithManager(mgr ctrl.Manager) error { func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { gateway := new(gatewayv1.Gateway) if err := r.Get(ctx, req.NamespacedName, gateway); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } + if client.IgnoreNotFound(err) == nil { + gateway.Namespace = req.Namespace + gateway.Name = req.Name + if err := r.ControlPlaneClient.Delete(ctx, gateway); err != nil { + return ctrl.Result{}, err + } + } + return ctrl.Result{}, err + } + ns := gateway.GetNamespace() if !r.checkGatewayClass(gateway) { return ctrl.Result{}, nil } @@ -74,13 +87,31 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct } r.Log.Info("gateway has been accepted", "gateway", gateway.GetName()) + type status struct { + status bool + msg string + } + acceptStatus := status{ + status: true, + msg: acceptedMessage("gateway"), + } + tctx := &translator.TranslateContext{ + Secrets: make(map[types.NamespacedName]*corev1.Secret), + } + r.processListenerConfig(tctx, gateway, ns) + if err := r.ControlPlaneClient.Update(ctx, tctx, gateway); err != nil { + acceptStatus = status{ + status: false, + msg: err.Error(), + } + } ListenerStatuses, err := getListenerStatus(ctx, r.Client, gateway) if err != nil { return ctrl.Result{}, err } - accepted := SetGatewayConditionAccepted(gateway, true, acceptedMessage("gateway")) + accepted := SetGatewayConditionAccepted(gateway, acceptStatus.status, acceptStatus.msg) Programmed := SetGatewayConditionProgrammed(gateway, conditionProgrammedStatus, conditionProgrammedMsg) if accepted || Programmed || len(addrs) > 0 || len(ListenerStatuses) > 0 { if len(addrs) > 0 { @@ -183,3 +214,31 @@ func (r *GatewayReconciler) listGatewaysForHTTPRoute(_ context.Context, obj clie } return recs } + +func (r *GatewayReconciler) processListenerConfig(tctx *translator.TranslateContext, gateway *gatewayv1.Gateway, ns string) { + listeners := gateway.Spec.Listeners + for _, listener := range listeners { + if listener.TLS == nil || listener.TLS.CertificateRefs == nil { + continue + } + secret := corev1.Secret{} + for _, ref := range listener.TLS.CertificateRefs { + if ref.Namespace != nil { + ns = string(*ref.Namespace) + } + if ref.Kind != nil && *ref.Kind == gatewayv1.Kind("Secret") { + if err := r.Get(context.Background(), client.ObjectKey{ + Namespace: ns, + Name: string(ref.Name), + }, &secret); err != nil { + log.Error(err, "failed to get secret", "namespace", ns, "name", string(ref.Name)) + SetGatewayListenerConditionProgrammed(gateway, string(listener.Name), false, err.Error()) + SetGatewayListenerConditionResolvedRefs(gateway, string(listener.Name), false, err.Error()) + break + } + log.Info("Setting secret for listener", "listener", listener.Name, "secret", secret.Name, " namespace", ns) + tctx.Secrets[types.NamespacedName{Namespace: ns, Name: string(ref.Name)}] = &secret + } + } + } +} diff --git a/internal/controller/utils.go b/internal/controller/utils.go index fa7265f33..d20746288 100644 --- a/internal/controller/utils.go +++ b/internal/controller/utils.go @@ -43,6 +43,15 @@ func setGatewayCondition(gw *gatewayv1.Gateway, newCondition metav1.Condition) { gw.Status.Conditions = MergeCondition(gw.Status.Conditions, newCondition) } +func setListenerCondition(gw *gatewayv1.Gateway, listenerName string, newCondition metav1.Condition) { + for i, listener := range gw.Status.Listeners { + if listener.Name == gatewayv1.SectionName(listenerName) { + gw.Status.Listeners[i].Conditions = MergeCondition(listener.Conditions, newCondition) + return + } + } +} + func reconcileGatewaysMatchGatewayClass(gatewayClass client.Object, gateways []gatewayv1.Gateway) (recs []reconcile.Request) { for _, gateway := range gateways { if string(gateway.Spec.GatewayClassName) == gatewayClass.GetName() { @@ -91,6 +100,72 @@ func SetGatewayConditionAccepted(gw *gatewayv1.Gateway, status bool, message str return } +func SetGatewayListenerConditionAccepted(gw *gatewayv1.Gateway, listenerName string, status bool, message string) (ok bool) { + conditionStatus := metav1.ConditionTrue + if !status { + conditionStatus = metav1.ConditionFalse + } + + condition := metav1.Condition{ + Type: string(gatewayv1.ListenerConditionAccepted), + Status: conditionStatus, + Reason: string(gatewayv1.ListenerConditionAccepted), + ObservedGeneration: gw.GetGeneration(), + Message: message, + LastTransitionTime: metav1.Now(), + } + + if !IsConditionPresentAndEqual(gw.Status.Conditions, condition) { + setListenerCondition(gw, listenerName, condition) + ok = true + } + return +} + +func SetGatewayListenerConditionProgrammed(gw *gatewayv1.Gateway, listenerName string, status bool, message string) (ok bool) { + conditionStatus := metav1.ConditionTrue + if !status { + conditionStatus = metav1.ConditionFalse + } + + condition := metav1.Condition{ + Type: string(gatewayv1.ListenerConditionProgrammed), + Status: conditionStatus, + Reason: string(gatewayv1.ListenerReasonProgrammed), + ObservedGeneration: gw.GetGeneration(), + Message: message, + LastTransitionTime: metav1.Now(), + } + + if !IsConditionPresentAndEqual(gw.Status.Conditions, condition) { + setListenerCondition(gw, listenerName, condition) + ok = true + } + return +} + +func SetGatewayListenerConditionResolvedRefs(gw *gatewayv1.Gateway, listenerName string, status bool, message string) (ok bool) { + conditionStatus := metav1.ConditionTrue + if !status { + conditionStatus = metav1.ConditionFalse + } + + condition := metav1.Condition{ + Type: string(gatewayv1.ListenerConditionResolvedRefs), + Status: conditionStatus, + Reason: string(gatewayv1.ListenerReasonResolvedRefs), + ObservedGeneration: gw.GetGeneration(), + Message: message, + LastTransitionTime: metav1.Now(), + } + + if !IsConditionPresentAndEqual(gw.Status.Conditions, condition) { + setListenerCondition(gw, listenerName, condition) + ok = true + } + return +} + func SetGatewayConditionProgrammed(gw *gatewayv1.Gateway, status bool, message string) (ok bool) { conditionStatus := metav1.ConditionTrue if !status { @@ -288,21 +363,17 @@ func checkRouteAcceptedByListener( return false, gatewayv1.RouteReasonNoMatchingParent, nil } } - if parentRef.Port != nil { if *parentRef.Port != listener.Port { return false, gatewayv1.RouteReasonNoMatchingParent, nil } } - if !routeMatchesListenerType(route, listener) { return false, gatewayv1.RouteReasonNoMatchingParent, nil } - if !routeHostnamesIntersectsWithListenerHostname(route, listener) { return false, gatewayv1.RouteReasonNoMatchingListenerHostname, nil } - if ok, err := routeMatchesListenerAllowedRoutes(ctx, mgrc, route, listener.AllowedRoutes, gateway.Namespace, parentRef.Namespace); err != nil { return false, gatewayv1.RouteReasonNotAllowedByListeners, fmt.Errorf("failed matching listener %s to a route %s for gateway %s: %w", listener.Name, route.GetName(), gateway.Name, err, @@ -480,7 +551,6 @@ func getAttachedRoutesForListener(ctx context.Context, mgrc client.Client, gatew if err := mgrc.List(ctx, &httpRouteList); err != nil { return 0, err } - var attachedRoutes int32 for _, route := range httpRouteList.Items { route := route @@ -534,7 +604,6 @@ func getListenerStatus( if err != nil { return nil, err } - var ( reasonResolvedRef = string(gatewayv1.ListenerReasonResolvedRefs) statusResolvedRef = metav1.ConditionTrue diff --git a/internal/controlplane/controlplane.go b/internal/controlplane/controlplane.go index 5a6b10841..68362d3ee 100644 --- a/internal/controlplane/controlplane.go +++ b/internal/controlplane/controlplane.go @@ -2,6 +2,7 @@ package controlplane import ( "context" + "fmt" "sigs.k8s.io/controller-runtime/pkg/client" gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" @@ -9,6 +10,7 @@ import ( "github.com/api7/api7-ingress-controller/internal/controller/config" "github.com/api7/api7-ingress-controller/internal/controlplane/translator" "github.com/api7/api7-ingress-controller/pkg/dashboard" + "github.com/api7/gopkg/pkg/log" ) type Controlplane interface { @@ -49,6 +51,8 @@ func (d *dashboardClient) Update(ctx context.Context, tctx *translator.Translate switch obj := obj.(type) { case *gatewayv1.HTTPRoute: result, err = d.translator.TranslateGatewayHTTPRoute(tctx, obj.DeepCopy()) + case *gatewayv1.Gateway: + result, err = d.translator.TranslateGateway(tctx, obj.DeepCopy()) } if err != nil { return err @@ -65,41 +69,99 @@ func (d *dashboardClient) Update(ctx context.Context, tctx *translator.Translate return err } } + for _, ssl := range result.SSL { + // to avoid duplication + ssl.Snis = arrayUniqueElements(ssl.Snis, []string{}) + if len(ssl.Snis) == 1 && ssl.Snis[0] == "*" { + log.Warnf("wildcard hostname is not allowed in ssl object. Skipping SSL creation for %s: %s", obj.GetObjectKind().GroupVersionKind().Kind, obj.GetName()) + return nil + } + ssl.Snis = removeWildcard(ssl.Snis) + oldssl, err := d.c.Cluster(name).SSL().Get(ctx, ssl.Cert) + if err != nil || oldssl == nil { + if _, err := d.c.Cluster(name).SSL().Create(ctx, ssl); err != nil { + return fmt.Errorf("failed to create ssl for sni %+v: %w", ssl.Snis, err) + } + } else { + // array union is done to avoid host duplication + ssl.Snis = arrayUniqueElements(ssl.Snis, oldssl.Snis) + if _, err := d.c.Cluster(name).SSL().Update(ctx, ssl); err != nil { + return fmt.Errorf("failed to update ssl for sni %+v: %w", ssl.Snis, err) + } + } + } return nil } +func removeWildcard(snis []string) []string { + newSni := make([]string, 0) + for _, sni := range snis { + if sni != "*" { + newSni = append(newSni, sni) + } + } + return newSni +} + +func arrayUniqueElements(arr1 []string, arr2 []string) []string { + // return a union of elements from both array + presentEle := make(map[string]bool) + newArr := make([]string, 0) + for _, ele := range arr1 { + if !presentEle[ele] { + presentEle[ele] = true + newArr = append(newArr, ele) + } + } + for _, ele := range arr2 { + if !presentEle[ele] { + presentEle[ele] = true + newArr = append(newArr, ele) + } + } + return newArr +} + func (d *dashboardClient) Delete(ctx context.Context, obj client.Object) error { clusters := d.c.ListClusters() + kindLabel := dashboard.ListByKindLabelOptions{ + Kind: obj.GetObjectKind().GroupVersionKind().Kind, + Namespace: obj.GetNamespace(), + Name: obj.GetName(), + } for _, cluster := range clusters { - routes, _ := cluster.Route().List(ctx, dashboard.ListOptions{ - From: dashboard.ListFromCache, - Args: []interface{}{ - "label", - obj.GetObjectKind().GroupVersionKind().Kind, - obj.GetNamespace(), - obj.GetName(), - }, - }) + switch obj.(type) { + case *gatewayv1.Gateway: + ssls, _ := cluster.SSL().List(ctx, dashboard.ListOptions{ + From: dashboard.ListFromCache, + KindLabel: kindLabel, + }) + for _, ssl := range ssls { + if err := cluster.SSL().Delete(ctx, ssl); err != nil { + return err + } + } + case *gatewayv1.HTTPRoute: + routes, _ := cluster.Route().List(ctx, dashboard.ListOptions{ + From: dashboard.ListFromCache, + KindLabel: kindLabel, + }) - for _, route := range routes { - if err := cluster.Route().Delete(ctx, route); err != nil { - return err + for _, route := range routes { + if err := cluster.Route().Delete(ctx, route); err != nil { + return err + } } - } - services, _ := cluster.Service().List(ctx, dashboard.ListOptions{ - From: dashboard.ListFromCache, - Args: []interface{}{ - "label", - obj.GetObjectKind().GroupVersionKind().Kind, - obj.GetNamespace(), - obj.GetName(), - }, - }) + services, _ := cluster.Service().List(ctx, dashboard.ListOptions{ + From: dashboard.ListFromCache, + KindLabel: kindLabel, + }) - for _, service := range services { - if err := cluster.Service().Delete(ctx, service); err != nil { - return err + for _, service := range services { + if err := cluster.Service().Delete(ctx, service); err != nil { + return err + } } } } diff --git a/internal/controlplane/translator/gateway.go b/internal/controlplane/translator/gateway.go index 6047e993a..1278dbf28 100644 --- a/internal/controlplane/translator/gateway.go +++ b/internal/controlplane/translator/gateway.go @@ -1 +1,147 @@ package translator + +import ( + "crypto/x509" + "encoding/pem" + "fmt" + + v1 "github.com/api7/api7-ingress-controller/api/dashboard/v1" + "github.com/api7/api7-ingress-controller/internal/controlplane/label" + "github.com/api7/api7-ingress-controller/internal/id" + "github.com/api7/gopkg/pkg/log" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" +) + +func (t *Translator) TranslateGateway(tctx *TranslateContext, obj *gatewayv1.Gateway) (*TranslateResult, error) { + result := &TranslateResult{} + for _, listener := range obj.Spec.Listeners { + if listener.TLS != nil { + tctx.GatewayTLSConfig = append(tctx.GatewayTLSConfig, *listener.TLS) + ssl, err := t.translateSecret(tctx, listener, obj) + if err != nil { + return nil, fmt.Errorf("failed to translate secret: %w", err) + } + result.SSL = append(result.SSL, ssl...) + } + } + return result, nil +} + +func (t *Translator) translateSecret(tctx *TranslateContext, listener gatewayv1.Listener, obj *gatewayv1.Gateway) ([]*v1.Ssl, error) { + if tctx.Secrets == nil { + return nil, nil + } + if listener.TLS.CertificateRefs == nil { + return nil, fmt.Errorf("no certificateRefs found in listener %s", listener.Name) + } + sslObjs := make([]*v1.Ssl, 0) + switch *listener.TLS.Mode { + case gatewayv1.TLSModeTerminate: + for _, ref := range listener.TLS.CertificateRefs { + ns := obj.GetNamespace() + if ref.Namespace != nil { + ns = string(*ref.Namespace) + } + if listener.TLS.CertificateRefs[0].Kind != nil && *listener.TLS.CertificateRefs[0].Kind == "Secret" { + sslObj := &v1.Ssl{ + Snis: []string{}, + } + name := listener.TLS.CertificateRefs[0].Name + secret := tctx.Secrets[types.NamespacedName{Namespace: ns, Name: string(ref.Name)}] + if secret == nil { + continue + } + if secret.Data == nil { + log.Error("secret data is nil", "secret", secret) + return nil, fmt.Errorf("no secret data found for %s/%s", ns, name) + } + cert, key, err := extractKeyPair(secret, true) + if err != nil { + return nil, err + } + sslObj.Cert = string(cert) + sslObj.Key = string(key) + // Dashboard doesn't allow wildcard hostname + if listener.Hostname != nil && *listener.Hostname != "" { + sslObj.Snis = append(sslObj.Snis, string(*listener.Hostname)) + } + hosts, err := extractHost(cert) + if err != nil { + return nil, err + } + sslObj.Snis = append(sslObj.Snis, hosts...) + // Note: Dashboard doesn't allow duplicate certificate across ssl objects + sslObj.ID = id.GenID(sslObj.Cert) + sslObj.Labels = label.GenLabel(obj) + sslObjs = append(sslObjs, sslObj) + } + + } + // Only supported on TLSRoute. The certificateRefs field is ignored in this mode. + case gatewayv1.TLSModePassthrough: + return sslObjs, nil + default: + return nil, fmt.Errorf("unknown TLS mode %s", *listener.TLS.Mode) + } + + return sslObjs, nil +} + +func extractHost(cert []byte) ([]string, error) { + block, _ := pem.Decode(cert) + if block == nil { + return nil, errors.New("parse certificate: not in PEM format") + } + der, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, errors.Wrap(err, "parse certificate") + } + return der.DNSNames, nil +} + +func extractKeyPair(s *corev1.Secret, hasPrivateKey bool) ([]byte, []byte, error) { + if _, ok := s.Data["cert"]; ok { + return extractApisixSecretKeyPair(s, hasPrivateKey) + } else if _, ok := s.Data[corev1.TLSCertKey]; ok { + return extractKubeSecretKeyPair(s, hasPrivateKey) + } else if ca, ok := s.Data[corev1.ServiceAccountRootCAKey]; ok && !hasPrivateKey { + return ca, nil, nil + } else { + return nil, nil, errors.New("unknown secret format") + } +} + +func extractApisixSecretKeyPair(s *corev1.Secret, hasPrivateKey bool) (cert []byte, key []byte, err error) { + var ok bool + cert, ok = s.Data["cert"] + if !ok { + return nil, nil, errors.New("missing cert field") + } + + if hasPrivateKey { + key, ok = s.Data["key"] + if !ok { + return nil, nil, errors.New("missing key field") + } + } + return +} + +func extractKubeSecretKeyPair(s *corev1.Secret, hasPrivateKey bool) (cert []byte, key []byte, err error) { + var ok bool + cert, ok = s.Data[corev1.TLSCertKey] + if !ok { + return nil, nil, errors.New("missing cert field") + } + + if hasPrivateKey { + key, ok = s.Data[corev1.TLSPrivateKeyKey] + if !ok { + return nil, nil, errors.New("missing key field") + } + } + return +} diff --git a/internal/controlplane/translator/translator.go b/internal/controlplane/translator/translator.go index bf3c6072b..caa536be0 100644 --- a/internal/controlplane/translator/translator.go +++ b/internal/controlplane/translator/translator.go @@ -2,6 +2,7 @@ package translator import ( "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" discoveryv1 "k8s.io/api/discovery/v1" "k8s.io/apimachinery/pkg/types" gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" @@ -14,11 +15,14 @@ type Translator struct { } type TranslateContext struct { - BackendRefs []gatewayv1.BackendRef - EndpointSlices map[types.NamespacedName][]discoveryv1.EndpointSlice + BackendRefs []gatewayv1.BackendRef + EndpointSlices map[types.NamespacedName][]discoveryv1.EndpointSlice + GatewayTLSConfig []gatewayv1.GatewayTLSConfig + Secrets map[types.NamespacedName]*corev1.Secret } type TranslateResult struct { Routes []*v1.Route Services []*v1.Service + SSL []*v1.Ssl } diff --git a/internal/manager/controllers.go b/internal/manager/controllers.go index 5474317a7..b6f8886ca 100644 --- a/internal/manager/controllers.go +++ b/internal/manager/controllers.go @@ -29,9 +29,10 @@ func setupControllers(ctx context.Context, mgr manager.Manager, cpclient control Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("GatewayClass"), }, &controller.GatewayReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("Gateway"), + Client: mgr.GetClient(), + ControlPlaneClient: cpclient, + Scheme: mgr.GetScheme(), + Log: ctrl.LoggerFrom(ctx).WithName("controllers").WithName("Gateway"), }, &controller.HTTPRouteReconciler{ Client: mgr.GetClient(), diff --git a/pkg/dashboard/cache/cache.go b/pkg/dashboard/cache/cache.go index 09592e689..11f43efed 100644 --- a/pkg/dashboard/cache/cache.go +++ b/pkg/dashboard/cache/cache.go @@ -61,7 +61,7 @@ type Cache interface { // ListStreamRoutes lists all stream_route objects in cache. ListStreamRoutes() ([]*v1.StreamRoute, error) // ListSSL lists all ssl objects in cache. - ListSSL() ([]*v1.Ssl, error) + ListSSL(...interface{}) ([]*v1.Ssl, error) // ListUpstreams lists all upstreams in cache. ListServices(...interface{}) ([]*v1.Service, error) // ListGlobalRules lists all global_rule objects in cache. diff --git a/pkg/dashboard/cache/memdb.go b/pkg/dashboard/cache/memdb.go index 5c0167cf2..88e230da4 100644 --- a/pkg/dashboard/cache/memdb.go +++ b/pkg/dashboard/cache/memdb.go @@ -179,8 +179,8 @@ func (c *dbCache) ListRoutes(args ...interface{}) ([]*v1.Route, error) { return routes, nil } -func (c *dbCache) ListSSL() ([]*v1.Ssl, error) { - raws, err := c.list("ssl") +func (c *dbCache) ListSSL(args ...interface{}) ([]*v1.Ssl, error) { + raws, err := c.list("ssl", args...) if err != nil { return nil, err } diff --git a/pkg/dashboard/cache/noop_db.go b/pkg/dashboard/cache/noop_db.go index 1e821a150..4a8cee6f1 100644 --- a/pkg/dashboard/cache/noop_db.go +++ b/pkg/dashboard/cache/noop_db.go @@ -80,7 +80,7 @@ func (c *noopCache) ListRoutes(...interface{}) ([]*v1.Route, error) { return nil, nil } -func (c *noopCache) ListSSL() ([]*v1.Ssl, error) { +func (c *noopCache) ListSSL(...interface{}) ([]*v1.Ssl, error) { return nil, nil } diff --git a/pkg/dashboard/dashboard.go b/pkg/dashboard/dashboard.go index 5877024cc..eedfcd587 100644 --- a/pkg/dashboard/dashboard.go +++ b/pkg/dashboard/dashboard.go @@ -83,7 +83,7 @@ type Route interface { type SSL interface { // name is namespace_sslname Get(ctx context.Context, name string) (*v1.Ssl, error) - List(ctx context.Context) ([]*v1.Ssl, error) + List(ctx context.Context, args ...interface{}) ([]*v1.Ssl, error) Create(ctx context.Context, ssl *v1.Ssl) (*v1.Ssl, error) Delete(ctx context.Context, ssl *v1.Ssl) error Update(ctx context.Context, ssl *v1.Ssl) (*v1.Ssl, error) diff --git a/pkg/dashboard/nonexistentclient.go b/pkg/dashboard/nonexistentclient.go index 9a01dc9ed..6222d00c8 100644 --- a/pkg/dashboard/nonexistentclient.go +++ b/pkg/dashboard/nonexistentclient.go @@ -85,7 +85,7 @@ func (f *dummySSL) Get(_ context.Context, _ string) (*v1.Ssl, error) { return nil, ErrClusterNotExist } -func (f *dummySSL) List(_ context.Context) ([]*v1.Ssl, error) { +func (f *dummySSL) List(_ context.Context, _ ...interface{}) ([]*v1.Ssl, error) { return nil, ErrClusterNotExist } @@ -356,7 +356,7 @@ func (c *dummyCache) GetPluginConfig(_ string) (*v1.PluginConfig, error) { } func (c *dummyCache) ListRoutes(...interface{}) ([]*v1.Route, error) { return nil, nil } -func (c *dummyCache) ListSSL() ([]*v1.Ssl, error) { return nil, nil } +func (c *dummyCache) ListSSL(_ ...interface{}) ([]*v1.Ssl, error) { return nil, nil } func (c *dummyCache) ListServices(...interface{}) ([]*v1.Service, error) { return nil, nil } func (c *dummyCache) ListStreamRoutes() ([]*v1.StreamRoute, error) { return nil, nil } func (c *dummyCache) ListGlobalRules() ([]*v1.GlobalRule, error) { return nil, nil } diff --git a/pkg/dashboard/service.go b/pkg/dashboard/service.go index b7c668250..36726070a 100644 --- a/pkg/dashboard/service.go +++ b/pkg/dashboard/service.go @@ -57,8 +57,14 @@ var ( ) type ListOptions struct { - From ListFrom - Args []interface{} + From ListFrom + KindLabel ListByKindLabelOptions +} + +type ListByKindLabelOptions struct { + Kind string + Namespace string + Name string } // List is only used in cache warming up. So here just pass through @@ -74,7 +80,10 @@ func (u *serviceClient) List(ctx context.Context, listOptions ...interface{}) ([ zap.String("cluster", u.cluster.name), zap.String("url", u.url), ) - return u.cluster.cache.ListServices() + return u.cluster.cache.ListServices("label", + options.KindLabel.Kind, + options.KindLabel.Namespace, + options.KindLabel.Name) } log.Debugw("try to list upstreams in APISIX", diff --git a/pkg/dashboard/ssl.go b/pkg/dashboard/ssl.go index 69ec12e72..ef00f8e2a 100644 --- a/pkg/dashboard/ssl.go +++ b/pkg/dashboard/ssl.go @@ -33,15 +33,8 @@ type sslClient struct { } func newSSLClient(c *cluster) SSL { - if c.adminVersion == "v3" { - return &sslClient{ - url: c.baseURL + "/ssls", - cluster: c, - } - } - return &sslClient{ - url: c.baseURL + "/ssl", + url: c.baseURL + "/ssls", cluster: c, } } @@ -60,13 +53,29 @@ func (s *sslClient) Get(ctx context.Context, name string) (*v1.Ssl, error) { // List is only used in cache warming up. So here just pass through // to APISIX. -func (s *sslClient) List(ctx context.Context) ([]*v1.Ssl, error) { +func (s *sslClient) List(ctx context.Context, listOptions ...interface{}) ([]*v1.Ssl, error) { + var options ListOptions + if len(listOptions) > 0 { + options = listOptions[0].(ListOptions) + } + if options.From == ListFromCache { + log.Debugw("try to list ssls in cache", + zap.String("cluster", s.cluster.name), + zap.String("url", s.url), + ) + return s.cluster.cache.ListSSL( + "label", + options.KindLabel.Kind, + options.KindLabel.Namespace, + options.KindLabel.Name, + ) + } log.Debugw("try to list ssl in APISIX", zap.String("url", s.url), zap.String("cluster", s.cluster.name), ) url := s.url - sslItems, err := s.cluster.listResource(ctx, url, "ssl") + sslItems, err := s.cluster.listResource(ctx, url, "ssls") if err != nil { log.Errorf("failed to list ssl: %s", err) return nil, err @@ -82,6 +91,7 @@ func (s *sslClient) List(ctx context.Context) ([]*v1.Ssl, error) { ) return nil, err } + items = append(items, ssl) } @@ -103,7 +113,7 @@ func (s *sslClient) Create(ctx context.Context, obj *v1.Ssl) (*v1.Ssl, error) { } url := s.url + "/" + obj.ID log.Debugw("creating ssl", zap.ByteString("body", data), zap.String("url", url)) - resp, err := s.cluster.createResource(ctx, url, "ssl", data) + resp, err := s.cluster.createResource(ctx, url, "ssls", data) if err != nil { log.Errorf("failed to create ssl: %s", err) return nil, err @@ -130,7 +140,7 @@ func (s *sslClient) Delete(ctx context.Context, obj *v1.Ssl) error { return err } url := s.url + "/" + obj.ID - if err := s.cluster.deleteResource(ctx, url, "ssl"); err != nil { + if err := s.cluster.deleteResource(ctx, url, "ssls"); err != nil { return err } if err := s.cluster.cache.DeleteSSL(obj); err != nil { @@ -148,7 +158,7 @@ func (s *sslClient) Update(ctx context.Context, obj *v1.Ssl) (*v1.Ssl, error) { ctx, obj, url, - "ssl", + "ssls", s.cluster.updateResource, s.cluster.cache.InsertSSL, func(resp *getResponse) (*v1.Ssl, error) { diff --git a/pkg/id/idgen.go b/pkg/id/idgen.go new file mode 100644 index 000000000..96ae53471 --- /dev/null +++ b/pkg/id/idgen.go @@ -0,0 +1,19 @@ +package id + +import ( + "fmt" + "hash/crc32" + + "github.com/api7/api7-ingress-controller/pkg/utils" +) + +// GenID generates an ID according to the raw material. +func GenID(raw string) string { + if raw == "" { + return "" + } + p := utils.String2Byte(raw) + + res := crc32.ChecksumIEEE(p) + return fmt.Sprintf("%x", res) +} diff --git a/pkg/id/idgen_test.go b/pkg/id/idgen_test.go new file mode 100644 index 000000000..16cf216c3 --- /dev/null +++ b/pkg/id/idgen_test.go @@ -0,0 +1,15 @@ +package id + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGenID(t *testing.T) { + hash := GenID("") + assert.Len(t, hash, 0) + + assert.Equal(t, GenID("111"), GenID("111")) + assert.NotEqual(t, GenID("112"), GenID("111")) +} diff --git a/pkg/utils/s2b.go b/pkg/utils/s2b.go new file mode 100644 index 000000000..55d27b049 --- /dev/null +++ b/pkg/utils/s2b.go @@ -0,0 +1,8 @@ +package utils + +import "unsafe" + +// s2b converts string to a byte slice without memory allocation. +func String2Byte(s string) []byte { + return unsafe.Slice(unsafe.StringData(s), len(s)) +} diff --git a/pkg/utils/s2b_test.go b/pkg/utils/s2b_test.go new file mode 100644 index 000000000..e477a81a4 --- /dev/null +++ b/pkg/utils/s2b_test.go @@ -0,0 +1,32 @@ +package utils + +import ( + "reflect" + "testing" +) + +func TestString2Byte(t *testing.T) { + type args struct { + raw string + } + tests := []struct { + name string + args args + wantB []byte + }{ + { + name: "test-1", + args: args{ + raw: "a", + }, + wantB: []byte{'a'}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if gotB := String2Byte(tt.args.raw); !reflect.DeepEqual(gotB, tt.wantB) { + t.Errorf("String2byte() = %v, want %v", gotB, tt.wantB) + } + }) + } +} diff --git a/test/conformance/conformance_test.go b/test/conformance/conformance_test.go index 8a56d8eab..5e86831cb 100644 --- a/test/conformance/conformance_test.go +++ b/test/conformance/conformance_test.go @@ -18,6 +18,12 @@ import ( "sigs.k8s.io/yaml" ) +var skippedTestsForSSL = []string{ + // Reason: https://github.com/kubernetes-sigs/gateway-api/blob/5c5fc388829d24e8071071b01e8313ada8f15d9f/conformance/utils/suite/suite.go#L358. SAN includes '*' + tests.HTTPRouteHTTPSListener.ShortName, + tests.HTTPRouteRedirectPortAndScheme.ShortName, +} + var skippedTestsForTraditionalRoutes = []string{ // TODO: Support ReferenceGrant resource tests.HTTPRouteInvalidReferenceGrant.ShortName, @@ -68,7 +74,7 @@ func TestGatewayAPIConformance(t *testing.T) { opts.CleanupBaseResources = true opts.GatewayClassName = gatewayClassName opts.SupportedFeatures = sets.New(gatewaySupportedFeatures...) - opts.SkipTests = skippedTestsForTraditionalRoutes + opts.SkipTests = append(skippedTestsForSSL, skippedTestsForTraditionalRoutes...) opts.Implementation = conformancev1.Implementation{ Organization: "API7", Project: "api7-ingress-controller", diff --git a/test/e2e/gatewayapi/gateway.go b/test/e2e/gatewayapi/gateway.go index a71e8a315..36977e381 100644 --- a/test/e2e/gatewayapi/gateway.go +++ b/test/e2e/gatewayapi/gateway.go @@ -1,14 +1,109 @@ package gatewayapi import ( + "context" + "fmt" "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" "github.com/api7/api7-ingress-controller/test/e2e/scaffold" ) +const _secretName = "test-apisix-tls" + +var Cert = `-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIJALDqPppBVXQ3MA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNV +BAYTAkNOMRAwDgYDVQQIDAdKaWFuZ3N1MQ8wDQYDVQQHDAZTdXpob3UxEDAOBgNV +BAoMB2FwaTcuYWkxEDAOBgNVBAsMB2FwaTcuYWkxDzANBgNVBAMMBmp3LmNvbTAg +Fw0yMTA0MDkwNzEyMDBaGA8yMDUxMDQwMjA3MTIwMFowZTELMAkGA1UEBhMCQ04x +EDAOBgNVBAgMB0ppYW5nc3UxDzANBgNVBAcMBlN1emhvdTEQMA4GA1UECgwHYXBp +Ny5haTEQMA4GA1UECwwHYXBpNy5haTEPMA0GA1UEAwwGancuY29tMIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuEPPnUMlSw41CTdxUNxkQ4gAZ7cPotwY +Y6sVLGtWoR8gKFSZImQIor3UF+8HhN/ZOFRv5tSeeQ/MTE72cs2T5mp6eRU8OrSV +0npk/TpZfaCx7zobsfXB4YU1NZcVWKthFF5X8p//l5gxUMU8V4a01P0aDTmZ67wG +3Fhr0AC067GVYvdwp1yRt6TUUk8ha7JsiySchUIFhX5QMWmrSNhc1bDnHetejMFl +itFFPZkeYG89O/7Ca1K3ca/VVu+/IJ4h7fbF3rt4uP182cJdHl1L94dQSKCJukaW +v+xauWnm4hxOzBK7ImpYB/2eP2D33tmuCLeSv4S+bTG1l7hIN9C/xrYPzfun415h +M2jMK69aAkQL71xa+66kVxioJyNYogYz3ss5ruzDL8K/7bkdO0Zzqldd2+j8lkTl +X4csA+aMHF3v/U7hL/4Wdwi8ziwToRMq9KK9vuh+mPgcdtFGFml+sU+NQfJNm/BN +7fRMZKDIHLacSPE0GUkfW+x3dXOP2lWSZe/iOBZ0NOGNdrOnxTRTr7IH7DYU8aXF +w2GqfAFEQbD4wazCh1AI8lkZr6mPGB1q+HnF2IF7kkgXBHtI5U2KErgcX5BirIVe +v0Yg/OxbbymeTh/hNCcY1kJ1YUCbm9U3U6ZV+d8lj7dQHtugcAzWxSTwpBLVUPrO +eFuhSMLVblUCAwEAAaMjMCEwHwYDVR0RBBgwFoIIYXBpNi5jb22CCiouYXBpNi5j +b20wDQYJKoZIhvcNAQELBQADggIBAFgeSuMPpriYUrQByO3taiY1+56s+KoAmsyA +LH15n2+thAgorusX2g1Zd7UNBHBtVO8c+ihpQb+2PnmgTTGT70ndpRbV5F6124Mt +Hui/X0kjm76RYd1QKN1VFp0Zo+JVdRa+VhDsXWjO0VetINmFhNINFEJctyeHB8oi +aaDL0wZrevHh47hBqtnrmLl+QVG34aLBRhZ5953leiNvXHUJNaT0nLgf0j9p4esS +b2bx9uP4pFI1T9wcv/TE3K0rQbu/uqGY6MgznXHyi4qIK/I+WCa3fF2UZ5P/5EUM +k2ptQneYkLLUVwwmj8C04bYhYe7Z6jkYYp17ojxIP+ejOY1eiE8SYKNjKinmphrM +5aceqIyfbE4TPqvicNzIggA4yEMPbTA0PC/wqbCf61oMc15hwacdeIaQGiwsM+pf +DTk+GBxp3megx/+0XwTQbguleTlHnaaES+ma0vbl6a1rUK0YAUDUrcfFLv6EFtGD +6EHxFf7gH9sTfc2RiGhKxUhRbyEree+6INAvXy+AymVYmQmKuAFqkDQJ+09bTfm8 +bDs+00FijzHFBvC8cIhNffj0qqiv35g+9FTwnE9qpunlrtKG/sMgEXX6m8kL1YQ8 +m5DPGhyEZyt5Js2kzzo8TyINPKmrqriYuiD4p4EH13eSRs3ayanQh6ckC7lb+WXq +3IrSc5hO +-----END CERTIFICATE-----` + +var Key = `-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY-----` + +func createSecret(s *scaffold.Scaffold, secretName string) { + err := s.NewKubeTlsSecret(secretName, Cert, Key) + assert.Nil(GinkgoT(), err, "create secret error") +} + var _ = Describe("Test Gateway", func() { s := scaffold.NewScaffold(&scaffold.Options{ ControllerName: "gateway.api7.io/api7-ingress-controller", @@ -84,4 +179,117 @@ spec: Expect(gwyaml).To(ContainSubstring(`status: Unknown`), "checking Gateway condition status") }) }) + + Context("Gateway SSL", func() { + It("Check if SSL resource was created", func() { + secretName := _secretName + host := "api6.com" + createSecret(s, secretName) + var defaultGatewayClass = ` +apiVersion: gateway.networking.k8s.io/v1 +kind: GatewayClass +metadata: + name: api7 +spec: + controllerName: "gateway.api7.io/api7-ingress-controller" +` + + var defaultGateway = fmt.Sprintf(` +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: api7ee +spec: + gatewayClassName: api7 + listeners: + - name: http1 + protocol: HTTPS + port: 443 + hostname: %s + tls: + certificateRefs: + - kind: Secret + group: "" + name: %s +`, host, secretName) + By("create GatewayClass") + err := s.CreateResourceFromStringWithNamespace(defaultGatewayClass, "") + Expect(err).NotTo(HaveOccurred(), "creating GatewayClass") + time.Sleep(5 * time.Second) + + By("create Gateway") + err = s.CreateResourceFromString(defaultGateway) + Expect(err).NotTo(HaveOccurred(), "creating Gateway") + time.Sleep(10 * time.Second) + + tls, err := s.DefaultDataplaneResource().SSL().List(context.Background()) + assert.Nil(GinkgoT(), err, "list tls error") + assert.Len(GinkgoT(), tls, 1, "tls number not expect") + assert.Equal(GinkgoT(), Cert, tls[0].Cert, "tls cert not expect") + assert.Equal(GinkgoT(), []string{host, "*.api6.com"}, tls[0].Snis) + }) + + Context("Gateway SSL with and without hostname", func() { + It("Check if SSL resource was created", func() { + secretName := _secretName + createSecret(s, secretName) + var defaultGatewayClass = ` +apiVersion: gateway.networking.k8s.io/v1 +kind: GatewayClass +metadata: + name: api7 +spec: + controllerName: "gateway.api7.io/api7-ingress-controller" +` + + var defaultGateway = fmt.Sprintf(` +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: same-namespace-with-https-listener +spec: + gatewayClassName: api7 + listeners: + - name: https + port: 443 + protocol: HTTPS + allowedRoutes: + namespaces: + from: Same + tls: + certificateRefs: + - group: "" + kind: Secret + name: %s + - name: https-with-hostname + port: 443 + hostname: api6.com + protocol: HTTPS + allowedRoutes: + namespaces: + from: Same + tls: + certificateRefs: + - group: "" + kind: Secret + name: %s +`, secretName, secretName) + By("create GatewayClass") + err := s.CreateResourceFromStringWithNamespace(defaultGatewayClass, "") + Expect(err).NotTo(HaveOccurred(), "creating GatewayClass") + time.Sleep(5 * time.Second) + + By("create Gateway") + err = s.CreateResourceFromString(defaultGateway) + Expect(err).NotTo(HaveOccurred(), "creating Gateway") + time.Sleep(10 * time.Second) + + tls, err := s.DefaultDataplaneResource().SSL().List(context.Background()) + assert.Nil(GinkgoT(), err, "list tls error") + assert.Len(GinkgoT(), tls, 1, "tls number not expect") + assert.Equal(GinkgoT(), Cert, tls[0].Cert, "tls cert not expect") + }) + }) + }) + }) diff --git a/test/e2e/gatewayapi/httproute.go b/test/e2e/gatewayapi/httproute.go index e7ed63d02..01281f01a 100644 --- a/test/e2e/gatewayapi/httproute.go +++ b/test/e2e/gatewayapi/httproute.go @@ -37,6 +37,24 @@ spec: protocol: HTTP port: 80 ` + var defautlGatewayHTTPS = ` +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: api7ee +spec: + gatewayClassName: %s + listeners: + - name: http1 + protocol: HTTPS + port: 443 + hostname: api6.com + tls: + certificateRefs: + - kind: Secret + group: "" + name: test-apisix-tls +` var ResourceApplied = func(resourType, resourceName, resourceRaw string, observedGeneration int) { Expect(s.CreateResourceFromString(resourceRaw)). @@ -56,7 +74,7 @@ spec: ) time.Sleep(1 * time.Second) } - var beforeEach = func() { + var beforeEachHTTP = func() { By("create GatewayClass") gatewayClassName := fmt.Sprintf("api7-%d", time.Now().Unix()) err := s.CreateResourceFromStringWithNamespace(fmt.Sprintf(defautlGatewayClass, gatewayClassName, s.GetControllerName()), "") @@ -81,6 +99,78 @@ spec: Expect(gwyaml).To(ContainSubstring("message: the gateway has been accepted by the api7-ingress-controller"), "checking Gateway condition message") } + var beforeEachHTTPS = func() { + secretName := _secretName + createSecret(s, secretName) + By("create GatewayClass") + gatewayClassName := fmt.Sprintf("api7-%d", time.Now().Unix()) + err := s.CreateResourceFromStringWithNamespace(fmt.Sprintf(defautlGatewayClass, gatewayClassName, s.GetControllerName()), "") + Expect(err).NotTo(HaveOccurred(), "creating GatewayClass") + time.Sleep(5 * time.Second) + + By("check GatewayClass condition") + gcyaml, err := s.GetResourceYaml("GatewayClass", gatewayClassName) + Expect(err).NotTo(HaveOccurred(), "getting GatewayClass yaml") + Expect(gcyaml).To(ContainSubstring(`status: "True"`), "checking GatewayClass condition status") + Expect(gcyaml).To(ContainSubstring("message: the gatewayclass has been accepted by the api7-ingress-controller"), "checking GatewayClass condition message") + + By("create Gateway") + err = s.CreateResourceFromString(fmt.Sprintf(defautlGatewayHTTPS, gatewayClassName)) + Expect(err).NotTo(HaveOccurred(), "creating Gateway") + time.Sleep(5 * time.Second) + + By("check Gateway condition") + gwyaml, err := s.GetResourceYaml("Gateway", "api7ee") + Expect(err).NotTo(HaveOccurred(), "getting Gateway yaml") + Expect(gwyaml).To(ContainSubstring(`status: "True"`), "checking Gateway condition status") + Expect(gwyaml).To(ContainSubstring("message: the gateway has been accepted by the api7-ingress-controller"), "checking Gateway condition message") + } + Context("HTTPRoute with HTTPS Gateway", func() { + var exactRouteByGet = ` +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: httpbin +spec: + parentRefs: + - name: api7ee + hostnames: + - api6.com + rules: + - matches: + - path: + type: Exact + value: /get + backendRefs: + - name: httpbin-service-e2e-test + port: 80 +` + + BeforeEach(beforeEachHTTPS) + + It("Create/Updtea/Delete HTTPRoute", func() { + By("create HTTPRoute") + ResourceApplied("HTTPRoute", "httpbin", exactRouteByGet, 1) + + By("access dataplane to check the HTTPRoute") + s.NewAPISIXHttpsClient("api6.com"). + GET("/get"). + WithHost("api6.com"). + Expect(). + Status(200) + By("delete HTTPRoute") + err := s.DeleteResourceFromString(exactRouteByGet) + Expect(err).NotTo(HaveOccurred(), "deleting HTTPRoute") + time.Sleep(5 * time.Second) + + s.NewAPISIXHttpsClient("api6.com"). + GET("/get"). + WithHost("api6.com"). + Expect(). + Status(404) + }) + }) + Context("HTTPRoute Base", func() { var exactRouteByGet = ` @@ -103,7 +193,7 @@ spec: port: 80 ` - BeforeEach(beforeEach) + BeforeEach(beforeEachHTTP) It("Create/Updtea/Delete HTTPRoute", func() { By("create HTTPRoute") @@ -198,7 +288,7 @@ spec: - name: httpbin-service-e2e-test port: 80 ` - BeforeEach(beforeEach) + BeforeEach(beforeEachHTTP) It("HTTPRoute Exact Match", func() { By("create HTTPRoute") @@ -368,7 +458,7 @@ spec: statusCode: 301 ` - BeforeEach(beforeEach) + BeforeEach(beforeEachHTTP) It("HTTPRoute RequestHeaderModifier", func() { By("create HTTPRoute") @@ -565,7 +655,7 @@ spec: ` BeforeEach(func() { - beforeEach() + beforeEachHTTP() s.DeployNginx(framework.NginxOptions{ Namespace: s.Namespace(), })