diff --git a/examples/01_ssh-service-one-pool/input.json b/examples/01_ssh-service-one-pool/input.json deleted file mode 100644 index c67121929..000000000 --- a/examples/01_ssh-service-one-pool/input.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "lb_uuid": "58622a8d-54a2-4b0c-8b5f-8de7dff29f6f", - "lb_ip_address": "86.75.30.9", - "slug": "my-ssh-loadbalancer", - "assignments": [ - { - "uuid":"8a48a7a9-b17b-4ac0-89d5-6c2b7976e24f", - "frontend": - { - "uuid":"16dd23d7-d3ab-42c8-a645-3169f2659a0b", - "port": 22 - }, - "pools": [ - { - "uuid": "49faa4a3-8d0b-4a7a-8bb9-7ed1b5995e49", - "name": "ssh-service-a", - "origins": [ - { - "uuid": "c0a80101-0000-0000-0000-000000000001", - "name": "svr1-2222", - "address": "1.2.3.4", - "enabled": true, - "port": "2222" - }, - { - "uuid": "c0a80101-0000-0000-0000-000000000002", - "name": "svr1-222", - "address": "1.2.3.4", - "enabled": true, - "port": "222", - "weight": 2 - }, - { - "uuid":"c0a80101-0000-0000-0000-000000000003", - "name": "svr2", - "address": "4.3.2.1", - "enabled": false, - "port": "2222" - } - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/examples/01_ssh-service-one-pool/result.cfg b/examples/01_ssh-service-one-pool/result.cfg deleted file mode 100644 index 5691e8b58..000000000 --- a/examples/01_ssh-service-one-pool/result.cfg +++ /dev/null @@ -1,31 +0,0 @@ -global - master-worker - chroot /usr/share/haproxy - user haproxy - maxconn 200 - pidfile /run/haproxy.pid - stats socket /var/run/haproxy.sock mode 660 level admin expose-fd listeners - log 127.0.0.1 local0 - -defaults - log global - mode tcp - option tcplog - retries 3 - timeout connect 5s - timeout client 50s - timeout server 50s - -program dataplaneapi - command dataplaneapi -f dataplaneapi.hcl - no option start-on-reload - -backend 8a48a7a9-b17b-4ac0-89d5-6c2b7976e24f - server c0a80101-0000-0000-0000-000000000001 1.2.3.4:2222 check port 2222 - server c0a80101-0000-0000-0000-000000000002 1.2.3.4:222 check port 222 - server c0a80101-0000-0000-0000-000000000003 4.3.2.1:2222 check port 2222 disabled - -frontend 16dd23d7-d3ab-42c8-a645-3169f2659a0b - bind ipv4@:2222 - use_backend 8a48a7a9-b17b-4ac0-89d5-6c2b7976e24f - diff --git a/examples/02_ssh-service-two-pools/input.json b/examples/02_ssh-service-two-pools/input.json deleted file mode 100644 index a524c0f0e..000000000 --- a/examples/02_ssh-service-two-pools/input.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "lb_uuid": "58622a8d-54a2-4b0c-8b5f-8de7dff29f6f", - "lb_ip_address": "86.75.30.9", - "slug": "my-ssh-loadbalancer", - "assignments": [ - { - "uuid":"8a48a7a9-b17b-4ac0-89d5-6c2b7976e24f", - "frontend": - { - "uuid":"16dd23d7-d3ab-42c8-a645-3169f2659a0b", - "port": 22 - }, - "pools": [ - { - "uuid": "49faa4a3-8d0b-4a7a-8bb9-7ed1b5995e49", - "name": "ssh-service-a", - "origins": [ - { - "uuid": "c0a80101-0000-0000-0000-000000000001", - "name": "svr1-2222", - "address": "1.2.3.4", - "enabled": true, - "port": "2222" - }, - { - "uuid": "c0a80101-0000-0000-0000-000000000002", - "name": "svr1-222", - "address": "1.2.3.4", - "enabled": true, - "port": "222", - "weight": 2 - }, - { - "uuid":"c0a80101-0000-0000-0000-000000000003", - "name": "svr2", - "address": "4.3.2.1", - "enabled": false, - "port": "2222" - } - ] - }, - { - "uuid": "c9bd57ac-6d88-4786-849e-0b228c17d645", - "name": "ssh-service-b", - "origins": [ - { - "uuid": "b1982331-0000-0000-0000-000000000001", - "name": "svr1-2222", - "address": "7.8.9.0", - "enabled": true, - "port": "2222" - } - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/examples/02_ssh-service-two-pools/result.cfg b/examples/02_ssh-service-two-pools/result.cfg deleted file mode 100644 index bafc0415b..000000000 --- a/examples/02_ssh-service-two-pools/result.cfg +++ /dev/null @@ -1,33 +0,0 @@ -global - master-worker - chroot /usr/share/haproxy - user haproxy - maxconn 200 - pidfile /run/haproxy.pid - stats socket /var/run/haproxy.sock mode 660 level admin expose-fd listeners - log 127.0.0.1 local0 - -defaults - log global - mode tcp - option tcplog - retries 3 - timeout connect 5s - timeout client 50s - timeout server 50s - -program dataplaneapi - command dataplaneapi -f dataplaneapi.hcl - no option start-on-reload - -backend 8a48a7a9-b17b-4ac0-89d5-6c2b7976e24f - server c0a80101-0000-0000-0000-000000000001 1.2.3.4:2222 check port 2222 - server c0a80101-0000-0000-0000-000000000002 1.2.3.4:222 check port 222 - server c0a80101-0000-0000-0000-000000000003 4.3.2.1:2222 check port 2222 disabled - server b1982331-0000-0000-0000-000000000001 7.8.9.0:2222 check port 2222 - -frontend 16dd23d7-d3ab-42c8-a645-3169f2659a0b - mode tcp - bind ipv4@:2222 - use_backend 8a48a7a9-b17b-4ac0-89d5-6c2b7976e24f - diff --git a/examples/03_http-and-https/input.json b/examples/03_http-and-https/input.json deleted file mode 100644 index 3f346323e..000000000 --- a/examples/03_http-and-https/input.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "lb_uuid": "a522bc95-2a74-4005-919d-6ae0a5be056d", - "lb_ip_address": "86.75.30.9", - "slug": "my-app-loadbalancer", - "assignments": [ - { - "uuid":"3da05271-c64c-480c-8c1e-f37eceb66ef5", - "frontend": - { - "uuid":"16dd23d7-d3ab-42c8-a645-3169f2659a0b", - "port": 80 - }, - "pools": [ - { - "uuid": "49faa4a3-8d0b-4a7a-8bb9-7ed1b5995e49", - "name": "ssh-service-a", - "origins": [ - { - "uuid": "c0a80101-0000-0000-0000-000000000001", - "name": "svr1", - "address": "3.1.4.1", - "enabled": true, - "port": "80" - } - ] - } - ] - }, - { - "uuid":"c1a3be07-afd7-4a67-9c53-ade6d7c58bd9", - "frontend": - { - "uuid":"8ca812cc-9c3d-4fed-95be-40a773f7d876", - "port": 443 - }, - "pools": [ - { - "uuid": "d94ad98b-b074-4794-896f-d71ae3b7b0ac", - "name": "ssh-service-a", - "origins": [ - { - "uuid": "676a1536-0a17-4676-9296-ee957e5871c1", - "name": "svr1", - "address": "3.1.4.1", - "enabled": true, - "port": "443" - } - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/examples/03_http-and-https/result.cfg b/examples/03_http-and-https/result.cfg deleted file mode 100644 index 0a36263ac..000000000 --- a/examples/03_http-and-https/result.cfg +++ /dev/null @@ -1,39 +0,0 @@ -global - master-worker - chroot /usr/share/haproxy - user haproxy - maxconn 200 - pidfile /run/haproxy.pid - stats socket /var/run/haproxy.sock mode 660 level admin expose-fd listeners - log 127.0.0.1 local0 - -defaults - log global - mode tcp - option tcplog - retries 3 - timeout connect 5s - timeout client 50s - timeout server 50s - -program dataplaneapi - command dataplaneapi -f dataplaneapi.hcl - no option start-on-reload - -backend 3da05271-c64c-480c-8c1e-f37eceb66ef5 - mode tcp - server c0a80101-0000-0000-0000-000000000001 3.1.4.1:80 check port 80 - -frontend 16dd23d7-d3ab-42c8-a645-3169f2659a0b - mode tcp - bind ipv4@:80 - use_backend 3da05271-c64c-480c-8c1e-f37eceb66ef5 - -backend c1a3be07-afd7-4a67-9c53-ade6d7c58bd9 - mode tcp - server 676a1536-0a17-4676-9296-ee957e5871c1 3.1.4.1:443 check port 443 - -frontend 8ca812cc-9c3d-4fed-95be-40a773f7d876 - mode tcp - bind ipv4@:443 - use_backend c1a3be07-afd7-4a67-9c53-ade6d7c58bd9 diff --git a/examples/blank.cfg b/examples/blank.cfg deleted file mode 100644 index d715081fb..000000000 --- a/examples/blank.cfg +++ /dev/null @@ -1,22 +0,0 @@ -global - master-worker - chroot /usr/share/haproxy - user haproxy - maxconn 200 - pidfile /run/haproxy.pid - stats socket /var/run/haproxy.sock mode 660 level admin expose-fd listeners - log 127.0.0.1 local0 - -defaults - log global - mode tcp - option tcplog - retries 3 - timeout connect 5s - timeout client 50s - timeout server 50s - - -program dataplaneapi - command dataplaneapi -f dataplaneapi.hcl - no option start-on-reload diff --git a/examples/datplaneapi.hcl b/examples/datplaneapi.hcl deleted file mode 100644 index bbd267ee1..000000000 --- a/examples/datplaneapi.hcl +++ /dev/null @@ -1,33 +0,0 @@ -config_version = 2 - -name = "$podname" - -mode = "single" - -dataplaneapi { - host = "127.0.0.1" - port = 5555 - - user "admin" { - insecure = true - password = "adminpwd" - } - - transaction { - transaction_dir = "/tmp/haproxy" - } - - advertised {} -} - -haproxy { - config_file = "/etc/haproxy/haproxy.cfg" - haproxy_bin = "haproxy" - - reload { - reload_delay = 15 - reload_cmd = "kill SIGUSR 1" - restart_cmd = "systemctl restart haproxy" - reload_strategy = "custom" - } -} \ No newline at end of file diff --git a/go.mod b/go.mod index 7ef794460..545444593 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/hasura/go-graphql-client v0.10.0 github.com/labstack/echo/v4 v4.11.1 - github.com/labstack/gommon v0.4.0 github.com/lib/pq v1.10.9 github.com/mattn/go-sqlite3 v1.14.17 github.com/mitchellh/go-homedir v1.1.0 @@ -67,7 +66,7 @@ require ( github.com/google/go-cmp v0.5.9 // indirect github.com/google/uuid v1.3.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.3 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -86,6 +85,7 @@ require ( github.com/labstack/echo v3.3.10+incompatible // indirect github.com/labstack/echo-contrib v0.15.0 // indirect github.com/labstack/echo-jwt/v4 v4.2.0 // indirect + github.com/labstack/gommon v0.4.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -106,7 +106,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc4 // indirect github.com/opencontainers/runc v1.1.7 // indirect - github.com/pelletier/go-toml/v2 v2.0.9 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect @@ -132,18 +132,17 @@ require ( github.com/vmihailenco/tagparser v0.1.2 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zclconf/go-cty v1.8.0 // indirect - go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.42.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // indirect - go.opentelemetry.io/otel v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/jaeger v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect - go.opentelemetry.io/otel/sdk v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0 // indirect + go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.44.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0 // indirect + go.opentelemetry.io/otel v1.18.0 // indirect + go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.18.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.18.0 // indirect + go.opentelemetry.io/otel/metric v1.18.0 // indirect + go.opentelemetry.io/otel/sdk v1.18.0 // indirect + go.opentelemetry.io/otel/trace v1.18.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.step.sm/crypto v0.35.1 // indirect go.uber.org/multierr v1.11.0 // indirect @@ -157,7 +156,7 @@ require ( golang.org/x/tools v0.13.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230815205213-6bfd019c3878 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230815205213-6bfd019c3878 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832 // indirect google.golang.org/grpc v1.58.1 // indirect google.golang.org/protobuf v1.31.0 // indirect diff --git a/go.sum b/go.sum index 43b16ce17..a4fbe7157 100644 --- a/go.sum +++ b/go.sum @@ -108,7 +108,6 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= @@ -267,8 +266,8 @@ github.com/graph-gophers/graphql-go v1.5.0 h1:fDqblo50TEpD0LY7RXk/LFVYEVqo3+tXMN github.com/graph-gophers/graphql-go v1.5.0/go.mod h1:YtmJZDLbF1YYNrlNAuiO5zAStUWc3XZT07iGsVqe1Os= github.com/graph-gophers/graphql-transport-ws v0.0.2 h1:DbmSkbIGzj8SvHei6n8Mh9eLQin8PtA8xY9eCzjRpvo= github.com/graph-gophers/graphql-transport-ws v0.0.2/go.mod h1:5BVKvFzOd2BalVIBFfnfmHjpJi/MZ5rOj8G55mXvZ8g= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 h1:dygLcbEBA+t/P7ck6a8AkXv6juQ4cK0RHBoh32jxhHM= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2/go.mod h1:Ap9RLCIJVtgQg1/BBgVEfypOAySvvlcpcVQkSzJCH4Y= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -445,8 +444,8 @@ github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYB github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk= github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= -github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= -github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -475,8 +474,6 @@ github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncj github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y= @@ -545,9 +542,6 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8= -github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= -github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= @@ -563,8 +557,6 @@ github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vb github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/wundergraph/graphql-go-tools v1.66.4 h1:yRvXYi0jjTghi5zimTluqHXAmyS7JVlGzTlxY6aL0sI= github.com/wundergraph/graphql-go-tools v1.66.4/go.mod h1:obaEJWub7088qodhKbSGHyhRVnHlBP5M9HigN/oalLE= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= 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= @@ -585,34 +577,32 @@ 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.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.42.0 h1:sYefIhrd/A3fO8rmr0vy2tgCLoR8CsbMqwbcUa70x00= -go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.42.0/go.mod h1:5Ll2ndRzg9UNUrj1n+v4ZCcrD/SYy7BnVrlCQXECowA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 h1:pginetY7+onl4qN1vl0xW/V/v6OBZ0vVdH+esuJgvmM= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0/go.mod h1:XiYsayHc36K3EByOO6nbAXnAWbrUxdjUROCEeeROOH8= -go.opentelemetry.io/contrib/propagators/b3 v1.17.0 h1:ImOVvHnku8jijXqkwCSyYKRDt2YrnGXD4BbhcpfbfJo= -go.opentelemetry.io/contrib/propagators/b3 v1.17.0/go.mod h1:IkfUfMpKWmynvvE0264trz0sf32NRTZL4nuAN9AbWRc= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= -go.opentelemetry.io/otel/exporters/jaeger v1.16.0 h1:YhxxmXZ011C0aDZKoNw+juVWAmEfv/0W2XBOv9aHTaA= -go.opentelemetry.io/otel/exporters/jaeger v1.16.0/go.mod h1:grYbBo/5afWlPpdPZYhyn78Bk04hnvxn2+hvxQhKIQM= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0/go.mod h1:vLarbg68dH2Wa77g71zmKQqlQ8+8Rq3GRG31uc0WcWI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 h1:cbsD4cUcviQGXdw8+bo5x2wazq10SKz8hEbtCRPcU78= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0/go.mod h1:JgXSGah17croqhJfhByOLVY719k1emAXC8MVhCIJlRs= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 h1:TVQp/bboR4mhZSav+MdgXB8FaRho1RC8UwVn3T0vjVc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0/go.mod h1:I33vtIe0sR96wfrUcilIzLoA3mLHhRmz9S9Te0S3gDo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0 h1:iqjq9LAB8aK++sKVcELezzn655JnBNdsDhghU4G/So8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0/go.mod h1:hGXzO5bhhSHZnKvrDaXB82Y9DRFour0Nz/KrBh7reWw= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= -go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= -go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= +go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.44.0 h1:9n9+SOwuCyZ0L8SbQYjZ5H+GKojHN3Kl8pBLwBUQqhk= +go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.44.0/go.mod h1:Wa9/q2K5L+ftWke2iekGNqVzwBWqyhI5OhtHKU7Qe04= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0 h1:KfYpVmrjI7JuToy5k8XV3nkapjWx48k4E4JOtVstzQI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0/go.mod h1:SeQhzAEccGVZVEy7aH87Nh0km+utSpo1pTv6eMMop48= +go.opentelemetry.io/contrib/propagators/b3 v1.19.0 h1:ulz44cpm6V5oAeg5Aw9HyqGFMS6XM7untlMEhD7YzzA= +go.opentelemetry.io/contrib/propagators/b3 v1.19.0/go.mod h1:OzCmE2IVS+asTI+odXQstRGVfXQ4bXv9nMBRK0nNyqQ= +go.opentelemetry.io/otel v1.18.0 h1:TgVozPGZ01nHyDZxK5WGPFB9QexeTMXEH7+tIClWfzs= +go.opentelemetry.io/otel v1.18.0/go.mod h1:9lWqYO0Db579XzVuCKFNPDl4s73Voa+zEck3wHaAYQI= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 h1:IAtl+7gua134xcV3NieDhJHjjOVeJhXAnYf/0hswjUY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0/go.mod h1:w+pXobnBzh95MNIkeIuAKcHe/Uu/CX2PKIvBP6ipKRA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 h1:yE32ay7mJG2leczfREEhoW3VfSZIvHaB+gvVo1o8DQ8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0/go.mod h1:G17FHPDLt74bCI7tJ4CMitEk4BXTYG4FW6XUpkPBXa4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.18.0 h1:6pu8ttx76BxHf+xz/H77AUZkPF3cwWzXqAUsXhVKI18= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.18.0/go.mod h1:IOmXxPrxoxFMXdNy7lfDmE8MzE61YPcurbUm0SMjerI= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.18.0 h1:hSWWvDjXHVLq9DkmB+77fl8v7+t+yYiS+eNkiplDK54= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.18.0/go.mod h1:zG7KQql1WjZCaUJd+L/ReSYx4bjbYJxg5ws9ws+mYes= +go.opentelemetry.io/otel/metric v1.18.0 h1:JwVzw94UYmbx3ej++CwLUQZxEODDj/pOuTCvzhtRrSQ= +go.opentelemetry.io/otel/metric v1.18.0/go.mod h1:nNSpsVDjWGfb7chbRLUNW+PBNdcSTHD4Uu5pfFMOI0k= +go.opentelemetry.io/otel/sdk v1.18.0 h1:e3bAB0wB3MljH38sHzpV/qWrOTCFrdZF2ct9F8rBkcY= +go.opentelemetry.io/otel/sdk v1.18.0/go.mod h1:1RCygWV7plY2KmdskZEDDBs4tJeHG92MdHZIluiYs/M= go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI= go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= +go.opentelemetry.io/otel/trace v1.18.0 h1:NY+czwbHbmndxojTEKiSMHkG2ClNH2PwmcHrdo0JY10= +go.opentelemetry.io/otel/trace v1.18.0/go.mod h1:T2+SGJGuYZY3bjj5rgh/hN7KIrlpWC5nS8Mjvzckz+0= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.step.sm/crypto v0.35.1 h1:QAZZ7Q8xaM4TdungGSAYw/zxpyH4fMYTkfaXVV9H7pY= @@ -962,8 +952,8 @@ google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20230815205213-6bfd019c3878 h1:Iveh6tGCJkHAjJgEqUQYGDGgbwmhjoAOz8kO/ajxefY= google.golang.org/genproto v0.0.0-20230815205213-6bfd019c3878/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto/googleapis/api v0.0.0-20230815205213-6bfd019c3878 h1:WGq4lvB/mlicysM/dUT3SBvijH4D3sm/Ny1A4wmt2CI= -google.golang.org/genproto/googleapis/api v0.0.0-20230815205213-6bfd019c3878/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= +google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q= +google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832 h1:o4LtQxebKIJ4vkzyhtD2rfUNZ20Zf0ik5YVP5E7G7VE= google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= diff --git a/internal/graphapi/loadbalancer.resolvers.go b/internal/graphapi/loadbalancer.resolvers.go index ffe7618e8..7362ec994 100644 --- a/internal/graphapi/loadbalancer.resolvers.go +++ b/internal/graphapi/loadbalancer.resolvers.go @@ -8,12 +8,13 @@ import ( "context" "database/sql" - "go.infratographer.com/load-balancer-api/internal/ent/generated" - "go.infratographer.com/load-balancer-api/internal/ent/generated/port" - "go.infratographer.com/load-balancer-api/internal/ent/generated/predicate" "go.infratographer.com/permissions-api/pkg/permissions" "go.infratographer.com/x/events" "go.infratographer.com/x/gidx" + + "go.infratographer.com/load-balancer-api/internal/ent/generated" + "go.infratographer.com/load-balancer-api/internal/ent/generated/port" + "go.infratographer.com/load-balancer-api/internal/ent/generated/predicate" ) // LoadBalancerCreate is the resolver for the loadBalancerCreate field. @@ -24,7 +25,12 @@ func (r *mutationResolver) LoadBalancerCreate(ctx context.Context, input generat lb, err := r.client.LoadBalancer.Create().SetInput(input).Save(ctx) if err != nil { - return nil, err + if generated.IsValidationError(err) { + return nil, err + } + + r.logger.Errorw("failed to create loadbalancer", "error", err) + return nil, ErrInternalServerError } return &LoadBalancerCreatePayload{LoadBalancer: lb}, nil @@ -32,26 +38,48 @@ func (r *mutationResolver) LoadBalancerCreate(ctx context.Context, input generat // LoadBalancerUpdate is the resolver for the loadBalancerUpdate field. func (r *mutationResolver) LoadBalancerUpdate(ctx context.Context, id gidx.PrefixedID, input generated.UpdateLoadBalancerInput) (*LoadBalancerUpdatePayload, error) { + logger := r.logger.With("loadbalancerID", id.String()) + + // check gidx format + if _, err := gidx.Parse(id.String()); err != nil { + return nil, err + } + if err := permissions.CheckAccess(ctx, id, actionLoadBalancerUpdate); err != nil { return nil, err } lb, err := r.client.LoadBalancer.Get(ctx, id) if err != nil { - return nil, err + if generated.IsNotFound(err) { + return nil, err + } + + logger.Errorw("failed to get loadbalancer", "error", err) + return nil, ErrInternalServerError } lb, err = lb.Update().SetInput(input).Save(ctx) if err != nil { - return nil, err + if generated.IsValidationError(err) { + return nil, err + } + + logger.Errorw("failed to update loadbalancer", "error", err) + return nil, ErrInternalServerError } return &LoadBalancerUpdatePayload{LoadBalancer: lb}, nil } // LoadBalancerDelete is the resolver for the loadBalancerDelete field. -func (r *mutationResolver) LoadBalancerDelete(ctx context.Context, id gidx.PrefixedID) (ldbp *LoadBalancerDeletePayload, err error) { - logger := r.logger.With("loadbalancer", id) +func (r *mutationResolver) LoadBalancerDelete(ctx context.Context, id gidx.PrefixedID) (*LoadBalancerDeletePayload, error) { + logger := r.logger.With("loadbalancerID", id.String()) + + // check gidx format + if _, err := gidx.Parse(id.String()); err != nil { + return nil, err + } if err := permissions.CheckAccess(ctx, id, actionLoadBalancerDelete); err != nil { return nil, err @@ -98,7 +126,7 @@ func (r *mutationResolver) LoadBalancerDelete(ctx context.Context, id gidx.Prefi for _, p := range ports { if err = tx.Port.DeleteOne(p).Exec(ctx); err != nil { - logger.Errorw("failed to delete port", "port", p.ID, "error", err) + logger.Errorw("failed to delete port", "loadbalancerPortID", p.ID, "error", err) return nil, ErrInternalServerError } } @@ -127,9 +155,26 @@ func (r *mutationResolver) LoadBalancerDelete(ctx context.Context, id gidx.Prefi // LoadBalancer is the resolver for the loadBalancer field. func (r *queryResolver) LoadBalancer(ctx context.Context, id gidx.PrefixedID) (*generated.LoadBalancer, error) { + logger := r.logger.With("loadbalancerID", id.String()) + + // check gidx format + if _, err := gidx.Parse(id.String()); err != nil { + return nil, err + } + if err := permissions.CheckAccess(ctx, id, actionLoadBalancerGet); err != nil { return nil, err } - return r.client.LoadBalancer.Get(ctx, id) + lb, err := r.client.LoadBalancer.Get(ctx, id) + if err != nil { + if generated.IsNotFound(err) { + return nil, err + } + + logger.Errorw("failed to get loadbalancer", "error", err) + return nil, ErrInternalServerError + } + + return lb, nil } diff --git a/internal/graphapi/loadbalancer_test.go b/internal/graphapi/loadbalancer_test.go index e1dde2e9e..e9647a726 100644 --- a/internal/graphapi/loadbalancer_test.go +++ b/internal/graphapi/loadbalancer_test.go @@ -50,6 +50,11 @@ func TestQuery_loadBalancer(t *testing.T) { QueryID: gidx.MustNewID("testing"), errorMsg: "load_balancer not found", }, + { + TestName: "invalid gidx format", + QueryID: "test-invalid-id", + errorMsg: "invalid id", + }, } for _, tt := range testCases { @@ -164,16 +169,17 @@ func TestUpdate_loadBalancer(t *testing.T) { lb := (&LoadBalancerBuilder{}).MustNew(ctx) updateName := gofakeit.DomainName() - emptyName := "" testCases := []struct { TestName string + ID gidx.PrefixedID Input graphclient.UpdateLoadBalancerInput ExpectedLB *ent.LoadBalancer errorMsg string }{ { TestName: "updates loadbalancer", + ID: lb.ID, Input: graphclient.UpdateLoadBalancerInput{Name: &updateName}, ExpectedLB: &ent.LoadBalancer{ Name: updateName, @@ -184,14 +190,27 @@ func TestUpdate_loadBalancer(t *testing.T) { }, { TestName: "fails to update name to empty", - Input: graphclient.UpdateLoadBalancerInput{Name: &emptyName}, + ID: lb.ID, + Input: graphclient.UpdateLoadBalancerInput{Name: newString("")}, errorMsg: "value is less than the required length", }, + { + TestName: "fails to update loadbalancer that does not exist", + ID: gidx.PrefixedID("loadbal-dne"), + Input: graphclient.UpdateLoadBalancerInput{Name: newString("loadbal-dne")}, + errorMsg: "load_balancer not found", + }, + { + TestName: "fails with invalid gidx", + ID: "test-invalid-id", + Input: graphclient.UpdateLoadBalancerInput{Name: newString("loadbal-dne")}, + errorMsg: "invalid id", + }, } for _, tt := range testCases { t.Run(tt.TestName, func(t *testing.T) { - resp, err := graphTestClient().LoadBalancerUpdate(ctx, lb.ID, tt.Input) + resp, err := graphTestClient().LoadBalancerUpdate(ctx, tt.ID, tt.Input) if tt.errorMsg != "" { require.Error(t, err) @@ -246,6 +265,11 @@ func TestDelete_loadBalancer(t *testing.T) { Input: gidx.PrefixedID(""), errorMsg: "load_balancer not found", }, + { + TestName: "fails with invalid gidx", + Input: "test-invalid-id", + errorMsg: "invalid id", + }, } for _, tt := range testCases { diff --git a/internal/graphapi/origin.resolvers.go b/internal/graphapi/origin.resolvers.go index 355fa3d49..4088c69a6 100644 --- a/internal/graphapi/origin.resolvers.go +++ b/internal/graphapi/origin.resolvers.go @@ -7,13 +7,21 @@ package graphapi import ( "context" - "go.infratographer.com/load-balancer-api/internal/ent/generated" "go.infratographer.com/permissions-api/pkg/permissions" "go.infratographer.com/x/gidx" + + "go.infratographer.com/load-balancer-api/internal/ent/generated" ) // LoadBalancerOriginCreate is the resolver for the loadBalancerOriginCreate field. func (r *mutationResolver) LoadBalancerOriginCreate(ctx context.Context, input generated.CreateLoadBalancerOriginInput) (*LoadBalancerOriginCreatePayload, error) { + logger := r.logger.With("poolID", input.PoolID) + + // check gidx format + if _, err := gidx.Parse(input.PoolID.String()); err != nil { + return nil, err + } + if err := permissions.CheckAccess(ctx, input.PoolID, actionLoadBalancerPoolUpdate); err != nil { return nil, err } @@ -21,12 +29,22 @@ func (r *mutationResolver) LoadBalancerOriginCreate(ctx context.Context, input g // check if pool exists _, err := r.client.Pool.Get(ctx, input.PoolID) if err != nil { - return nil, err + if generated.IsNotFound(err) { + return nil, err + } + + logger.Errorw("failed to get pool", "error", err) + return nil, ErrInternalServerError } origin, err := r.client.Origin.Create().SetInput(input).Save(ctx) if err != nil { - return nil, err + if generated.IsValidationError(err) { + return nil, err + } + + logger.Errorw("failed to create origin", "error", err) + return nil, ErrInternalServerError } return &LoadBalancerOriginCreatePayload{LoadBalancerOrigin: origin}, nil @@ -34,9 +52,21 @@ func (r *mutationResolver) LoadBalancerOriginCreate(ctx context.Context, input g // LoadBalancerOriginUpdate is the resolver for the loadBalancerOriginUpdate field. func (r *mutationResolver) LoadBalancerOriginUpdate(ctx context.Context, id gidx.PrefixedID, input generated.UpdateLoadBalancerOriginInput) (*LoadBalancerOriginUpdatePayload, error) { + logger := r.logger.With("originID", id.String()) + + // check gidx format + if _, err := gidx.Parse(id.String()); err != nil { + return nil, err + } + origin, err := r.client.Origin.Get(ctx, id) if err != nil { - return nil, err + if generated.IsNotFound(err) { + return nil, err + } + + logger.Errorw("failed to get origin", "error", err) + return nil, ErrInternalServerError } if err := permissions.CheckAccess(ctx, origin.PoolID, actionLoadBalancerPoolUpdate); err != nil { @@ -45,7 +75,12 @@ func (r *mutationResolver) LoadBalancerOriginUpdate(ctx context.Context, id gidx origin, err = origin.Update().SetInput(input).Save(ctx) if err != nil { - return nil, err + if generated.IsValidationError(err) { + return nil, err + } + + logger.Errorw("failed to update origin", "error", err) + return nil, ErrInternalServerError } return &LoadBalancerOriginUpdatePayload{LoadBalancerOrigin: origin}, nil @@ -53,9 +88,21 @@ func (r *mutationResolver) LoadBalancerOriginUpdate(ctx context.Context, id gidx // LoadBalancerOriginDelete is the resolver for the loadBalancerOriginDelete field. func (r *mutationResolver) LoadBalancerOriginDelete(ctx context.Context, id gidx.PrefixedID) (*LoadBalancerOriginDeletePayload, error) { + logger := r.logger.With("originID", id.String()) + + // check gidx format + if _, err := gidx.Parse(id.String()); err != nil { + return nil, err + } + origin, err := r.client.Origin.Get(ctx, id) if err != nil { - return nil, err + if generated.IsNotFound(err) { + return nil, err + } + + logger.Errorw("failed to get origin", "error", err) + return nil, ErrInternalServerError } if err := permissions.CheckAccess(ctx, origin.PoolID, actionLoadBalancerPoolUpdate); err != nil { @@ -63,7 +110,8 @@ func (r *mutationResolver) LoadBalancerOriginDelete(ctx context.Context, id gidx } if err := r.client.Origin.DeleteOneID(id).Exec(ctx); err != nil { - return nil, err + logger.Errorw("failed to delete origin", "error", err) + return nil, ErrInternalServerError } return &LoadBalancerOriginDeletePayload{DeletedID: id}, nil diff --git a/internal/graphapi/pool.resolvers.go b/internal/graphapi/pool.resolvers.go index f0ebac508..6e9df7680 100644 --- a/internal/graphapi/pool.resolvers.go +++ b/internal/graphapi/pool.resolvers.go @@ -7,9 +7,7 @@ package graphapi import ( "context" "database/sql" - "fmt" - "github.com/labstack/gommon/log" "go.infratographer.com/permissions-api/pkg/permissions" "go.infratographer.com/x/gidx" @@ -22,13 +20,21 @@ import ( // LoadBalancerPoolCreate is the resolver for the LoadBalancerPoolCreate field. func (r *mutationResolver) LoadBalancerPoolCreate(ctx context.Context, input generated.CreateLoadBalancerPoolInput) (*LoadBalancerPoolCreatePayload, error) { + logger := r.logger.With("ownerID", input.OwnerID) + + // check gidx owner format + if _, err := gidx.Parse(input.OwnerID.String()); err != nil { + return nil, err + } + if err := permissions.CheckAccess(ctx, input.OwnerID, actionLoadBalancerPoolCreate); err != nil { return nil, err } ids, err := r.client.Port.Query().Where(port.HasLoadBalancerWith(loadbalancer.OwnerIDEQ(input.OwnerID))).Where(port.IDIn(input.PortIDs...)).IDs(ctx) if err != nil { - return nil, err + logger.Errorw("failed to query input ports", "error", err) + return nil, ErrInternalServerError } if len(ids) < len(input.PortIDs) { @@ -37,13 +43,19 @@ func (r *mutationResolver) LoadBalancerPoolCreate(ctx context.Context, input gen for _, portId := range input.PortIDs { if err := permissions.CheckAccess(ctx, portId, actionLoadBalancerGet); err != nil { + logger.Errorw("failed to check access", "error", err, "loadbalancerPortID", portId) return nil, err } } pool, err := r.client.Pool.Create().SetInput(input).Save(ctx) if err != nil { - return nil, err + if generated.IsValidationError(err) { + return nil, err + } + + logger.Errorw("failed to create loadbalancer pool", "error", err) + return nil, ErrInternalServerError } return &LoadBalancerPoolCreatePayload{LoadBalancerPool: pool}, nil @@ -51,18 +63,31 @@ func (r *mutationResolver) LoadBalancerPoolCreate(ctx context.Context, input gen // LoadBalancerPoolUpdate is the resolver for the LoadBalancerPoolUpdate field. func (r *mutationResolver) LoadBalancerPoolUpdate(ctx context.Context, id gidx.PrefixedID, input generated.UpdateLoadBalancerPoolInput) (*LoadBalancerPoolUpdatePayload, error) { + logger := r.logger.With("loadbalancerPoolID", id) + + // check gidx format + if _, err := gidx.Parse(id.String()); err != nil { + return nil, err + } + if err := permissions.CheckAccess(ctx, id, actionLoadBalancerPoolUpdate); err != nil { return nil, err } pool, err := r.client.Pool.Get(ctx, id) if err != nil { - return nil, err + if generated.IsNotFound(err) { + return nil, err + } + + logger.Errorw("failed to get loadbalancer pool", "error", err) + return nil, ErrInternalServerError } ids, err := r.client.Port.Query().Where(port.HasLoadBalancerWith(loadbalancer.OwnerIDEQ(pool.OwnerID))).Where(port.IDIn(input.AddPortIDs...)).IDs(ctx) if err != nil { - return nil, err + logger.Errorw("failed to query input ports", "error", err) + return nil, ErrInternalServerError } if len(ids) < len(input.AddPortIDs) { @@ -71,13 +96,19 @@ func (r *mutationResolver) LoadBalancerPoolUpdate(ctx context.Context, id gidx.P for _, portId := range input.AddPortIDs { if err := permissions.CheckAccess(ctx, portId, actionLoadBalancerGet); err != nil { + logger.Errorw("failed to check access", "error", err, "loadbalancerPortID", portId) return nil, err } } pool, err = pool.Update().SetInput(input).Save(ctx) if err != nil { - return nil, err + if generated.IsValidationError(err) { + return nil, err + } + + logger.Errorw("failed to update loadbalancer pool", "error", err) + return nil, ErrInternalServerError } return &LoadBalancerPoolUpdatePayload{LoadBalancerPool: pool}, nil @@ -85,54 +116,61 @@ func (r *mutationResolver) LoadBalancerPoolUpdate(ctx context.Context, id gidx.P // LoadBalancerPoolDelete is the resolver for the loadBalancerPoolDelete field. func (r *mutationResolver) LoadBalancerPoolDelete(ctx context.Context, id gidx.PrefixedID) (*LoadBalancerPoolDeletePayload, error) { + logger := r.logger.With("loadbalancerPoolID", id) + + // check gidx format + if _, err := gidx.Parse(id.String()); err != nil { + return nil, err + } + if err := permissions.CheckAccess(ctx, id, actionLoadBalancerPoolDelete); err != nil { return nil, err } - // TODO: return the requestID echo generates or we could use the root trace id - var ( - err error - tx *generated.Tx - ) + if _, err := r.client.Pool.Get(ctx, id); err != nil { + if generated.IsNotFound(err) { + return nil, err + } - tx, err = r.client.BeginTx(ctx, &sql.TxOptions{}) + logger.Errorw("failed to get loadbalancer pool", "error", err) + return nil, ErrInternalServerError + } + + tx, err := r.client.BeginTx(ctx, &sql.TxOptions{}) if err != nil { - return nil, err + logger.Errorw("failed to begin transaction", "error", err) + return nil, ErrInternalServerError } - // todo: cleanup pool assigments + defer func() { + if err := tx.Rollback(); err != nil { + logger.Errorw("failed to rollback transaction", "error", err) + } + }() // cleanup origins associated with pool origins, err := tx.Origin.Query().Where(predicate.Origin(origin.PoolIDEQ(id))).All(ctx) if err != nil { - if rerr := tx.Rollback(); rerr != nil { - log.Error(fmt.Errorf("%w: %v", err, rerr).Error()) - } - return nil, err + logger.Errorw("failed to query origins", "error", err) + return nil, ErrInternalServerError } for _, o := range origins { if err = tx.Origin.DeleteOne(o).Exec(ctx); err != nil { - if rerr := tx.Rollback(); rerr != nil { - log.Error(fmt.Errorf("%w: %v", err, rerr).Error()) - } - return nil, err + logger.Errorw("failed to delete origin", "loadbalancerOriginID", o.ID, "error", err) + return nil, ErrInternalServerError } } // delete pool - if err = tx.Pool.DeleteOneID(id).Exec(ctx); err != nil { - if rerr := tx.Rollback(); rerr != nil { - log.Error(fmt.Errorf("%w: %v", err, rerr).Error()) - } - return nil, err + if err := tx.Pool.DeleteOneID(id).Exec(ctx); err != nil { + logger.Errorw("failed to delete loadbalancer pool", "error", err) + return nil, ErrInternalServerError } - if err = tx.Commit(); err != nil { - if rerr := tx.Rollback(); rerr != nil { - log.Error(fmt.Errorf("%w: %v", err, rerr).Error()) - } - return nil, err + if err := tx.Commit(); err != nil { + logger.Errorw("failed to commit transaction", "error", err) + return nil, ErrInternalServerError } return &LoadBalancerPoolDeletePayload{DeletedID: &id}, nil @@ -140,9 +178,26 @@ func (r *mutationResolver) LoadBalancerPoolDelete(ctx context.Context, id gidx.P // LoadBalancerPool is the resolver for the loadBalancerPool field. func (r *queryResolver) LoadBalancerPool(ctx context.Context, id gidx.PrefixedID) (*generated.Pool, error) { + logger := r.logger.With("loadbalancerPoolID", id.String()) + + // check gidx format + if _, err := gidx.Parse(id.String()); err != nil { + return nil, err + } + if err := permissions.CheckAccess(ctx, id, actionLoadBalancerPoolGet); err != nil { return nil, err } - return r.client.Pool.Get(ctx, id) + pool, err := r.client.Pool.Get(ctx, id) + if err != nil { + if generated.IsNotFound(err) { + return nil, err + } + + logger.Errorw("failed to get loadbalancer pool", "error", err) + return nil, ErrInternalServerError + } + + return pool, nil } diff --git a/internal/graphapi/pool_test.go b/internal/graphapi/pool_test.go index 9f9dceea1..3d0f76db7 100644 --- a/internal/graphapi/pool_test.go +++ b/internal/graphapi/pool_test.go @@ -47,11 +47,11 @@ func TestQueryPool(t *testing.T) { }, { TestName: "pool not found", - QueryID: gidx.MustNewID("testing"), + QueryID: gidx.MustNewID("loadpol"), errorMsg: "not found", }, { - TestName: "invalid pool query ID", + TestName: "invalid pool ID", QueryID: "an invalid pool id", errorMsg: "invalid id", }, @@ -193,12 +193,14 @@ func TestMutate_PoolUpdate(t *testing.T) { testCases := []struct { TestName string + ID gidx.PrefixedID Input graphclient.UpdateLoadBalancerPoolInput ExpectedPool ent.LoadBalancerPool errorMsg string }{ { TestName: "successfully updates name", + ID: pool1.ID, Input: graphclient.UpdateLoadBalancerPoolInput{ Name: newString("ImaPool"), }, @@ -210,6 +212,7 @@ func TestMutate_PoolUpdate(t *testing.T) { }, { TestName: "successfully updates protocol", + ID: pool1.ID, Input: graphclient.UpdateLoadBalancerPoolInput{ Name: newString("ImaPool"), Protocol: &updateProtocolUDP, @@ -222,13 +225,27 @@ func TestMutate_PoolUpdate(t *testing.T) { }, { TestName: "empty name", + ID: pool1.ID, Input: graphclient.UpdateLoadBalancerPoolInput{ Name: newString(""), }, errorMsg: "validator failed", }, + { + TestName: "fails with invalid gidx", + ID: gidx.PrefixedID("not a valid gidx"), + Input: graphclient.UpdateLoadBalancerPoolInput{}, + errorMsg: "invalid id", + }, + { + TestName: "fails to update pool that does not exist", + ID: gidx.MustNewID("loadpol"), + Input: graphclient.UpdateLoadBalancerPoolInput{}, + errorMsg: "not found", + }, { TestName: "fails to update pool with port with conflicting OwnerID", + ID: pool1.ID, Input: graphclient.UpdateLoadBalancerPoolInput{ Name: newString("ImaPool"), AddPortIDs: []gidx.PrefixedID{port.ID}, @@ -242,7 +259,7 @@ func TestMutate_PoolUpdate(t *testing.T) { tt := tt t.Run(tt.TestName, func(t *testing.T) { - updatedPoolResp, err := graphTestClient().LoadBalancerPoolUpdate(ctx, pool1.ID, tt.Input) + updatedPoolResp, err := graphTestClient().LoadBalancerPoolUpdate(ctx, tt.ID, tt.Input) if tt.errorMsg != "" { require.Error(t, err) assert.ErrorContains(t, err, tt.errorMsg) @@ -274,6 +291,8 @@ func TestMutate_PoolDelete(t *testing.T) { ctx = context.WithValue(ctx, permissions.CheckerCtxKey, permissions.DefaultAllowChecker) pool1 := (&PoolBuilder{Protocol: "tcp"}).MustNew(ctx) + pool2 := (&PoolBuilder{Protocol: "tcp"}).MustNew(ctx) + _ = (&OriginBuilder{PoolID: pool2.ID}).MustNew(ctx) testCases := []struct { TestName string @@ -285,15 +304,24 @@ func TestMutate_PoolDelete(t *testing.T) { DeleteID: pool1.ID, }, { - TestName: "invalid ID", + TestName: "fails with invalid gidx", DeleteID: "not a valid ID", errorMsg: "invalid id", }, { - TestName: "non-existent ID", - DeleteID: gidx.MustNewID(ownerPrefix), + TestName: "fails to delete pool that does not exist", + DeleteID: gidx.MustNewID("loadpol"), errorMsg: "not found", }, + { + TestName: "fails to delete empty pool id", + DeleteID: gidx.PrefixedID(""), + errorMsg: "not found", + }, + { + TestName: "deletes pool with associated origins", + DeleteID: pool2.ID, + }, } for _, tt := range testCases { diff --git a/internal/graphapi/port.resolvers.go b/internal/graphapi/port.resolvers.go index 34f46ddba..e973aea36 100644 --- a/internal/graphapi/port.resolvers.go +++ b/internal/graphapi/port.resolvers.go @@ -17,18 +17,38 @@ import ( // LoadBalancerPortCreate is the resolver for the loadBalancerPortCreate field. func (r *mutationResolver) LoadBalancerPortCreate(ctx context.Context, input generated.CreateLoadBalancerPortInput) (*LoadBalancerPortCreatePayload, error) { + logger := r.logger.With("loadbalancerID", input.LoadBalancerID, "loadbalancerPools", input.PoolIDs) + + // check gidx lb id format + if _, err := gidx.Parse(input.LoadBalancerID.String()); err != nil { + return nil, err + } + + // check gidx pool id format + for _, p := range input.PoolIDs { + if _, err := gidx.Parse(p.String()); err != nil { + return nil, err + } + } + if err := permissions.CheckAccess(ctx, input.LoadBalancerID, actionLoadBalancerUpdate); err != nil { return nil, err } lb, err := r.client.LoadBalancer.Get(ctx, input.LoadBalancerID) if err != nil { - return nil, err + if generated.IsNotFound(err) { + return nil, err + } + + logger.Errorw("failed to get loadbalancer", "error", err) + return nil, ErrInternalServerError } ids, err := r.client.Pool.Query().Where(pool.OwnerIDEQ(lb.OwnerID)).Where(pool.IDIn(input.PoolIDs...)).IDs(ctx) if err != nil { - return nil, err + logger.Errorw("failed to query input pools", "error", err) + return nil, ErrInternalServerError } if len(ids) < len(input.PoolIDs) { @@ -37,6 +57,7 @@ func (r *mutationResolver) LoadBalancerPortCreate(ctx context.Context, input gen for _, poolId := range input.PoolIDs { if err := permissions.CheckAccess(ctx, poolId, actionLoadBalancerPoolGet); err != nil { + logger.Errorw("failed to check access", "error", err, "loadbalancerPoolID", poolId) return nil, err } } @@ -46,8 +67,11 @@ func (r *mutationResolver) LoadBalancerPortCreate(ctx context.Context, input gen switch { case generated.IsConstraintError(err) && strings.Contains(err.Error(), "number"): return nil, ErrPortNumberInUse - default: + case generated.IsValidationError(err): return nil, err + default: + logger.Errorw("failed to create loadbalancer port", "error", err) + return nil, ErrInternalServerError } } @@ -56,22 +80,41 @@ func (r *mutationResolver) LoadBalancerPortCreate(ctx context.Context, input gen // LoadBalancerPortUpdate is the resolver for the loadBalancerPortUpdate field. func (r *mutationResolver) LoadBalancerPortUpdate(ctx context.Context, id gidx.PrefixedID, input generated.UpdateLoadBalancerPortInput) (*LoadBalancerPortUpdatePayload, error) { + logger := r.logger.With("loadbalancerPortID", id) + + // check gidx format + if _, err := gidx.Parse(id.String()); err != nil { + return nil, err + } + p, err := r.client.Port.Get(ctx, id) if err != nil { - return nil, err + if generated.IsNotFound(err) { + return nil, err + } + + logger.Errorw("failed to get loadbalancer port", "error", err) + return nil, ErrInternalServerError } + if err := permissions.CheckAccess(ctx, p.LoadBalancerID, actionLoadBalancerUpdate); err != nil { return nil, err } lb, err := r.client.LoadBalancer.Get(ctx, p.LoadBalancerID) if err != nil { - return nil, err + if generated.IsNotFound(err) { + return nil, err + } + + logger.Errorw("failed to get loadbalancer", "error", err) + return nil, ErrInternalServerError } ids, err := r.client.Pool.Query().Where(pool.OwnerIDEQ(lb.OwnerID)).Where(pool.IDIn(input.AddPoolIDs...)).IDs(ctx) if err != nil { - return nil, err + logger.Errorw("failed to query input pools", "error", err) + return nil, ErrInternalServerError } if len(ids) < len(input.AddPoolIDs) { @@ -80,16 +123,21 @@ func (r *mutationResolver) LoadBalancerPortUpdate(ctx context.Context, id gidx.P for _, poolId := range input.AddPoolIDs { if err := permissions.CheckAccess(ctx, poolId, actionLoadBalancerPoolGet); err != nil { + logger.Errorw("failed to check access", "error", err, "loadbalancerPoolID", poolId) return nil, err } } p, err = p.Update().SetInput(input).Save(ctx) if err != nil { - if generated.IsConstraintError(err) && strings.Contains(err.Error(), "number") { - return nil, ErrPortNumberInUse - } else { + switch { + case generated.IsValidationError(err): return nil, err + case generated.IsConstraintError(err) && strings.Contains(err.Error(), "number"): + return nil, ErrPortNumberInUse + default: + logger.Errorw("failed to update loadbalancer port", "error", err) + return nil, ErrInternalServerError } } @@ -98,9 +146,21 @@ func (r *mutationResolver) LoadBalancerPortUpdate(ctx context.Context, id gidx.P // LoadBalancerPortDelete is the resolver for the loadBalancerPortDelete field. func (r *mutationResolver) LoadBalancerPortDelete(ctx context.Context, id gidx.PrefixedID) (*LoadBalancerPortDeletePayload, error) { + logger := r.logger.With("loadbalancerPortID", id.String()) + + // check gidx format + if _, err := gidx.Parse(id.String()); err != nil { + return nil, err + } + p, err := r.client.Port.Get(ctx, id) if err != nil { - return nil, err + if generated.IsNotFound(err) { + return nil, err + } + + logger.Errorw("failed to get loadbalancer port", "error", err) + return nil, ErrInternalServerError } if err := permissions.CheckAccess(ctx, p.LoadBalancerID, actionLoadBalancerUpdate); err != nil { @@ -108,7 +168,8 @@ func (r *mutationResolver) LoadBalancerPortDelete(ctx context.Context, id gidx.P } if err := r.client.Port.DeleteOneID(id).Exec(ctx); err != nil { - return nil, err + logger.Errorw("failed to delete loadbalancer port", "error", err) + return nil, ErrInternalServerError } return &LoadBalancerPortDeletePayload{DeletedID: id}, nil diff --git a/internal/graphapi/port_test.go b/internal/graphapi/port_test.go index cfa0d0b2f..7676f5128 100644 --- a/internal/graphapi/port_test.go +++ b/internal/graphapi/port_test.go @@ -105,6 +105,16 @@ func TestCreate_LoadbalancerPort(t *testing.T) { }, errorMsg: "port number restricted", }, + { + TestName: "fails to create loadbalancer port with invalid pool id", + Input: graphclient.CreateLoadBalancerPortInput{ + Name: "lb-port", + LoadBalancerID: lb.ID, + Number: 1234, + PoolIDs: []gidx.PrefixedID{"not-a-valid-pool-id"}, + }, + errorMsg: "invalid id", + }, { TestName: "fails to create loadbalancer port with pool with conflicting OwnerID", Input: graphclient.CreateLoadBalancerPortInput{ @@ -166,11 +176,13 @@ func TestUpdate_LoadbalancerPort(t *testing.T) { testCases := []struct { TestName string Input graphclient.UpdateLoadBalancerPortInput + ID gidx.PrefixedID Expected *graphclient.LoadBalancerPort errorMsg string }{ { TestName: "fails to update loadbalancer port number to duplicate of another port", + ID: port.ID, Input: graphclient.UpdateLoadBalancerPortInput{ Number: newInt64(8080), }, @@ -178,6 +190,7 @@ func TestUpdate_LoadbalancerPort(t *testing.T) { }, { TestName: "fails to update loadbalancer port number to restricted port", + ID: port.ID, Input: graphclient.UpdateLoadBalancerPortInput{ Number: newInt64(1234), }, @@ -185,6 +198,7 @@ func TestUpdate_LoadbalancerPort(t *testing.T) { }, { TestName: "updates loadbalancer port name", + ID: port.ID, Input: graphclient.UpdateLoadBalancerPortInput{ Name: newString("lb-port"), }, @@ -195,6 +209,7 @@ func TestUpdate_LoadbalancerPort(t *testing.T) { }, { TestName: "updates loadbalancer port number", + ID: port.ID, Input: graphclient.UpdateLoadBalancerPortInput{ Number: newInt64(22), }, @@ -205,6 +220,7 @@ func TestUpdate_LoadbalancerPort(t *testing.T) { }, { TestName: "fails to update loadbalancer port name to empty", + ID: port.ID, Input: graphclient.UpdateLoadBalancerPortInput{ Name: newString(""), }, @@ -212,6 +228,7 @@ func TestUpdate_LoadbalancerPort(t *testing.T) { }, { TestName: "fails to update loadbalancer port number < min", + ID: port.ID, Input: graphclient.UpdateLoadBalancerPortInput{ Number: newInt64(0), }, @@ -219,13 +236,27 @@ func TestUpdate_LoadbalancerPort(t *testing.T) { }, { TestName: "fails to update loadbalancer port number > max", + ID: port.ID, Input: graphclient.UpdateLoadBalancerPortInput{ Number: newInt64(65536), }, errorMsg: "value out of range", }, + { + TestName: "fails to update port that does not exist", + ID: gidx.PrefixedID("loadprt-doesnotexist"), + Input: graphclient.UpdateLoadBalancerPortInput{}, + errorMsg: "not found", + }, + { + TestName: "fails to update port with invalid gidx", + ID: gidx.PrefixedID("not a valid gidx"), + Input: graphclient.UpdateLoadBalancerPortInput{}, + errorMsg: "invalid id", + }, { TestName: "fails to update loadbalancer port with pool with conflicting OwnerID", + ID: port.ID, Input: graphclient.UpdateLoadBalancerPortInput{ AddPoolIDs: []gidx.PrefixedID{poolBad.ID}, }, @@ -235,7 +266,7 @@ func TestUpdate_LoadbalancerPort(t *testing.T) { for _, tt := range testCases { t.Run(tt.TestName, func(t *testing.T) { - resp, err := graphTestClient().LoadBalancerPortUpdate(ctx, port.ID, tt.Input) + resp, err := graphTestClient().LoadBalancerPortUpdate(ctx, tt.ID, tt.Input) if tt.errorMsg != "" { require.Error(t, err) @@ -291,6 +322,11 @@ func TestDelete_LoadbalancerPort(t *testing.T) { Input: gidx.PrefixedID(""), errorMsg: "port not found", }, + { + TestName: "fails to delete with invalid gidx port ID", + Input: gidx.PrefixedID("not-a-valid-gidx"), + errorMsg: "invalid id", + }, } for _, tt := range testCases { diff --git a/internal/graphapi/provider.resolvers.go b/internal/graphapi/provider.resolvers.go index 394e9fdfa..f6365ed0f 100644 --- a/internal/graphapi/provider.resolvers.go +++ b/internal/graphapi/provider.resolvers.go @@ -7,20 +7,31 @@ package graphapi import ( "context" - "go.infratographer.com/load-balancer-api/internal/ent/generated" "go.infratographer.com/permissions-api/pkg/permissions" "go.infratographer.com/x/gidx" + + "go.infratographer.com/load-balancer-api/internal/ent/generated" ) // LoadBalancerProviderCreate is the resolver for the loadBalancerProviderCreate field. func (r *mutationResolver) LoadBalancerProviderCreate(ctx context.Context, input generated.CreateLoadBalancerProviderInput) (*LoadBalancerProviderCreatePayload, error) { + // check gidx owner format + if _, err := gidx.Parse(input.OwnerID.String()); err != nil { + return nil, err + } + if err := permissions.CheckAccess(ctx, input.OwnerID, actionLoadBalancerProviderCreate); err != nil { return nil, err } p, err := r.client.Provider.Create().SetInput(input).Save(ctx) if err != nil { - return nil, err + if generated.IsValidationError(err) { + return nil, err + } + + r.logger.Errorw("failed to create loadbalancer provider", "error", err) + return nil, ErrInternalServerError } return &LoadBalancerProviderCreatePayload{LoadBalancerProvider: p}, nil @@ -28,29 +39,59 @@ func (r *mutationResolver) LoadBalancerProviderCreate(ctx context.Context, input // LoadBalancerProviderUpdate is the resolver for the loadBalancerProviderUpdate field. func (r *mutationResolver) LoadBalancerProviderUpdate(ctx context.Context, id gidx.PrefixedID, input generated.UpdateLoadBalancerProviderInput) (*LoadBalancerProviderUpdatePayload, error) { + logger := r.logger.With("loadbalancerProviderID", id.String()) + + // check gidx format + if _, err := gidx.Parse(id.String()); err != nil { + return nil, err + } + if err := permissions.CheckAccess(ctx, id, actionLoadBalancerProviderUpdate); err != nil { return nil, err } p, err := r.client.Provider.Get(ctx, id) if err != nil { - return nil, err + if generated.IsNotFound(err) { + return nil, err + } + + logger.Errorw("failed to get loadbalancer provider", "error", err) + return nil, ErrInternalServerError } p, err = p.Update().SetInput(input).Save(ctx) if err != nil { - return nil, err + if generated.IsValidationError(err) { + return nil, err + } + + logger.Errorw("failed to update loadbalancer provider", "error", err) + return nil, ErrInternalServerError } + return &LoadBalancerProviderUpdatePayload{LoadBalancerProvider: p}, nil } // LoadBalancerProviderDelete is the resolver for the loadBalancerProviderDelete field. func (r *mutationResolver) LoadBalancerProviderDelete(ctx context.Context, id gidx.PrefixedID) (*LoadBalancerProviderDeletePayload, error) { + logger := r.logger.With("loadbalancerProviderID", id.String()) + + // check gidx format + if _, err := gidx.Parse(id.String()); err != nil { + return nil, err + } + if err := permissions.CheckAccess(ctx, id, actionLoadBalancerProviderDelete); err != nil { return nil, err } if err := r.client.Provider.DeleteOneID(id).Exec(ctx); err != nil { + if generated.IsNotFound(err) { + return nil, err + } + + logger.Errorw("failed to delete loadbalancer provider", "error", err) return nil, err } @@ -59,9 +100,26 @@ func (r *mutationResolver) LoadBalancerProviderDelete(ctx context.Context, id gi // LoadBalancerProvider is the resolver for the loadBalancerProvider field. func (r *queryResolver) LoadBalancerProvider(ctx context.Context, id gidx.PrefixedID) (*generated.Provider, error) { + logger := r.logger.With("loadbalancerProviderID", id.String()) + + // check gidx format + if _, err := gidx.Parse(id.String()); err != nil { + return nil, err + } + if err := permissions.CheckAccess(ctx, id, actionLoadBalancerProviderGet); err != nil { return nil, err } - return r.client.Provider.Get(ctx, id) + p, err := r.client.Provider.Get(ctx, id) + if err != nil { + if generated.IsNotFound(err) { + return nil, err + } + + logger.Errorw("failed to get loadbalancer provider", "error", err) + return nil, ErrInternalServerError + } + + return p, nil } diff --git a/internal/graphapi/provider_test.go b/internal/graphapi/provider_test.go index e60f727f1..3bd1574e7 100644 --- a/internal/graphapi/provider_test.go +++ b/internal/graphapi/provider_test.go @@ -44,6 +44,11 @@ func TestQuery_loadBalancerProvider(t *testing.T) { QueryID: gidx.MustNewID("testing"), errorMsg: "provider not found", }, + { + TestName: "Invalid load balancer provider ID", + QueryID: gidx.PrefixedID("invalid"), + errorMsg: "invalid id", + }, } for _, tt := range testCases { @@ -102,6 +107,11 @@ func TestCreate_Provider(t *testing.T) { Input: graphclient.CreateLoadBalancerProviderInput{Name: name, OwnerID: ""}, errorMsg: "value is less than the required length", }, + { + TestName: "fails to create provider with invalid ownerID", + Input: graphclient.CreateLoadBalancerProviderInput{Name: name, OwnerID: gidx.PrefixedID("invalid")}, + errorMsg: "invalid id", + }, } for _, tt := range testCases { @@ -139,16 +149,17 @@ func TestUpdate_Provider(t *testing.T) { prov := ProviderBuilder{}.MustNew(ctx) updateName := gofakeit.DomainName() - emptyName := "" testCases := []struct { TestName string + ID gidx.PrefixedID Input graphclient.UpdateLoadBalancerProviderInput ExpectedProvider *ent.LoadBalancerProvider errorMsg string }{ { TestName: "updates provider", + ID: prov.ID, Input: graphclient.UpdateLoadBalancerProviderInput{Name: &updateName}, ExpectedProvider: &ent.LoadBalancerProvider{ Name: updateName, @@ -158,14 +169,27 @@ func TestUpdate_Provider(t *testing.T) { }, { TestName: "fails to update name to empty", - Input: graphclient.UpdateLoadBalancerProviderInput{Name: &emptyName}, + ID: prov.ID, + Input: graphclient.UpdateLoadBalancerProviderInput{Name: newString("")}, errorMsg: "value is less than the required length", }, + { + TestName: "fails to update provider that does not exist", + ID: gidx.PrefixedID("loadpvd-dne"), + Input: graphclient.UpdateLoadBalancerProviderInput{}, + errorMsg: "provider not found", + }, + { + TestName: "fails to update provider with invalid id", + ID: gidx.PrefixedID("invalid"), + Input: graphclient.UpdateLoadBalancerProviderInput{}, + errorMsg: "invalid id", + }, } for _, tt := range testCases { t.Run(tt.TestName, func(t *testing.T) { - resp, err := graphTestClient().LoadBalancerProviderUpdate(ctx, prov.ID, tt.Input) + resp, err := graphTestClient().LoadBalancerProviderUpdate(ctx, tt.ID, tt.Input) if tt.errorMsg != "" { require.Error(t, err) @@ -215,11 +239,16 @@ func TestDelete_Provider(t *testing.T) { Input: gidx.PrefixedID(""), errorMsg: "provider not found", }, + { + TestName: "fails to delete invalid gidx id", + Input: gidx.PrefixedID("not-a-valid-gidx-id"), + errorMsg: "invalid id", + }, } for _, tt := range testCases { t.Run(tt.TestName, func(t *testing.T) { - resp, err := graphTestClient().LoadBalancerProviderDelete(ctx, prov.ID) + resp, err := graphTestClient().LoadBalancerProviderDelete(ctx, tt.Input) if tt.errorMsg != "" { require.Error(t, err)