From a1d363955b4c4a2ff9bddb821e43a955e370fc4c Mon Sep 17 00:00:00 2001 From: Krithika3 Date: Wed, 22 Jun 2022 13:54:50 -0700 Subject: [PATCH] feat: Merge UX server code (#67) * Moved the api server folder to numaflow Signed-off-by: Krithika Vijayakumar * Skipping routes test Signed-off-by: Krithika Vijayakumar Co-authored-by: Krithika Vijayakumar Signed-off-by: Derek Wang --- go.mod | 19 ++- go.sum | 39 +++++- server/apis/interface.go | 19 +++ server/apis/v1/handler.go | 248 +++++++++++++++++++++++++++++++++++ server/cmd/main.go | 59 +++++++++ server/routes/routes.go | 36 +++++ server/routes/routes_test.go | 34 +++++ 7 files changed, 445 insertions(+), 9 deletions(-) create mode 100644 server/apis/interface.go create mode 100644 server/apis/v1/handler.go create mode 100644 server/cmd/main.go create mode 100644 server/routes/routes.go create mode 100644 server/routes/routes_test.go diff --git a/go.mod b/go.mod index 7eeda3fdf9..960e9d6312 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,8 @@ require ( github.com/antonmedv/expr v1.9.0 github.com/fsnotify/fsnotify v1.5.1 github.com/gavv/httpexpect/v2 v2.3.1 + github.com/gin-contrib/static v0.0.2-0.20220606235426-ae09b2ea7e39 + github.com/gin-gonic/gin v1.8.1 github.com/go-redis/redis/v8 v8.11.4 github.com/go-swagger/go-swagger v0.28.0 github.com/gogo/protobuf v1.3.2 @@ -25,19 +27,20 @@ require ( github.com/soheilhy/cmux v0.1.5 github.com/spf13/cobra v1.2.1 github.com/spf13/viper v1.9.0 - github.com/stretchr/testify v1.7.1 + github.com/stretchr/testify v1.7.2 github.com/vmihailenco/msgpack/v5 v5.3.5 go.uber.org/atomic v1.9.0 go.uber.org/zap v1.19.1 google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5 google.golang.org/grpc v1.43.0 - google.golang.org/protobuf v1.27.1 + google.golang.org/protobuf v1.28.0 k8s.io/api v0.23.3 k8s.io/apimachinery v0.23.3 k8s.io/client-go v0.23.3 k8s.io/code-generator v0.23.3 k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 + k8s.io/metrics v0.23.3 k8s.io/utils v0.0.0-20211116205334-6203023598ed sigs.k8s.io/controller-runtime v0.11.1 sigs.k8s.io/controller-tools v0.8.0 @@ -66,6 +69,7 @@ require ( github.com/fatih/structs v1.0.0 // indirect github.com/felixge/httpsnoop v1.0.2 // indirect github.com/ghodss/yaml v1.0.0 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-logr/logr v1.2.0 // indirect github.com/go-openapi/analysis v0.20.1 // indirect github.com/go-openapi/errors v0.20.1 // indirect @@ -78,8 +82,12 @@ require ( github.com/go-openapi/strfmt v0.20.3 // indirect github.com/go-openapi/swag v0.19.15 // indirect github.com/go-openapi/validate v0.20.3 // indirect + github.com/go-playground/locales v0.14.0 // indirect + github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/go-playground/validator/v10 v10.10.0 // indirect github.com/go-stack/stack v1.8.1 // indirect github.com/gobuffalo/flect v0.2.3 // indirect + github.com/goccy/go-json v0.9.7 // indirect github.com/golang/glog v1.0.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect @@ -106,10 +114,11 @@ require ( github.com/klauspost/compress v1.15.1 // indirect github.com/kr/pretty v0.3.0 // indirect github.com/kr/text v0.2.0 // indirect + github.com/leodido/go-urn v1.2.1 // indirect github.com/magiconair/properties v1.8.5 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.8 // indirect - github.com/mattn/go-isatty v0.0.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/mapstructure v1.4.2 // indirect @@ -121,6 +130,7 @@ require ( github.com/nats-io/nuid v1.0.1 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/pelletier/go-toml v1.9.4 // indirect + github.com/pelletier/go-toml/v2 v2.0.1 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -139,6 +149,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.2.0 // indirect github.com/toqueteos/webbrowser v1.2.0 // indirect + github.com/ugorji/go/codec v1.2.7 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.37.0 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect @@ -165,7 +176,7 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.63.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.23.0 // indirect k8s.io/component-base v0.23.0 // indirect k8s.io/klog v0.2.0 // indirect diff --git a/go.sum b/go.sum index 693de9566a..1c9a04e3a5 100644 --- a/go.sum +++ b/go.sum @@ -212,6 +212,12 @@ github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSy github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-contrib/static v0.0.2-0.20220606235426-ae09b2ea7e39 h1:1xhHo07Z96hls7+cRH/07GGzkXcZobesXXspnIx7ks8= +github.com/gin-contrib/static v0.0.2-0.20220606235426-ae09b2ea7e39/go.mod h1:Cderg4Pr62hXlk54D5w96mao4lVrvm4eTlcD6csprTU= +github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -330,6 +336,14 @@ github.com/go-openapi/validate v0.20.1/go.mod h1:b60iJT+xNNLfaQJUqLI7946tYiFEOuE github.com/go-openapi/validate v0.20.2/go.mod h1:e7OJoKNgd0twXZwIn0A43tHbvIcr/rZIVCbJBpTUoY0= github.com/go-openapi/validate v0.20.3 h1:GZPPhhKSZrE8HjB4eEkoYAZmoWA4+tCemSgINH1/vKw= github.com/go-openapi/validate v0.20.3/go.mod h1:goDdqVGiigM3jChcrYJxD2joalke3ZXeftD16byIjA4= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0= +github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg= github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= @@ -366,6 +380,8 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -589,6 +605,8 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -614,8 +632,9 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -706,6 +725,8 @@ github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAv github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= +github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -821,8 +842,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= @@ -831,6 +853,9 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= +github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -944,6 +969,7 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -1397,8 +1423,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1433,8 +1460,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1472,6 +1499,8 @@ k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw= k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4= k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/metrics v0.23.3 h1:rX/RBOwqi0atFlTSlpbQ7CX5s/kfqGR9zEefCx9Rv1s= +k8s.io/metrics v0.23.3/go.mod h1:Ut8TvkbsO4oMVeUzaTArvPrcw9QRFLs2XNzUlORjdYE= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20211116205334-6203023598ed h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5fZ/shhbrgPUxDAE= diff --git a/server/apis/interface.go b/server/apis/interface.go new file mode 100644 index 0000000000..74f3bd17a4 --- /dev/null +++ b/server/apis/interface.go @@ -0,0 +1,19 @@ +package apis + +import "github.com/gin-gonic/gin" + +type Handler interface { + ListPipelines(c *gin.Context) + GetPipeline(c *gin.Context) + ListNamespaces(c *gin.Context) + ListInterStepBufferServices(c *gin.Context) + GetInterStepBufferService(c *gin.Context) + ListVerices(c *gin.Context) + GetVertex(c *gin.Context) + ListVertexPods(c *gin.Context) + PodLogs(c *gin.Context) + ListPodsMetrics(c *gin.Context) + GetPodMetrics(c *gin.Context) + ListPipelineEdges(c *gin.Context) + GetPipelineEdge(c *gin.Context) +} diff --git a/server/apis/v1/handler.go b/server/apis/v1/handler.go new file mode 100644 index 0000000000..958249ddb2 --- /dev/null +++ b/server/apis/v1/handler.go @@ -0,0 +1,248 @@ +package v1 + +import ( + "bufio" + "context" + "fmt" + "net/http" + "os" + "strconv" + + "github.com/gin-gonic/gin" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + metricsversiond "k8s.io/metrics/pkg/client/clientset/versioned" + "k8s.io/utils/pointer" + + dfv1 "github.com/numaproj/numaflow/pkg/apis/numaflow/v1alpha1" + dfv1versiond "github.com/numaproj/numaflow/pkg/client/clientset/versioned" + dfv1clients "github.com/numaproj/numaflow/pkg/client/clientset/versioned/typed/numaflow/v1alpha1" + daemonclient "github.com/numaproj/numaflow/pkg/daemon/client" +) + +type handler struct { + kubeClient kubernetes.Interface + metricsClient *metricsversiond.Clientset + numaflowClient dfv1clients.NumaflowV1alpha1Interface +} + +func NewHandler() (*handler, error) { + var restConfig *rest.Config + var err error + kubeconfig := os.Getenv("KUBECONFIG") + if kubeconfig == "" { + home, _ := os.UserHomeDir() + kubeconfig = home + "/.kube/config" + if _, err := os.Stat(kubeconfig); err != nil && os.IsNotExist(err) { + kubeconfig = "" + } + } + if kubeconfig != "" { + restConfig, err = clientcmd.BuildConfigFromFlags("", kubeconfig) + } else { + restConfig, err = rest.InClusterConfig() + } + if err != nil { + return nil, fmt.Errorf("failed to get kubeconfig, %w", err) + } + kubeClient, err := kubernetes.NewForConfig(restConfig) + if err != nil { + return nil, fmt.Errorf("failed to get kubeclient, %w", err) + } + metricsClient := metricsversiond.NewForConfigOrDie(restConfig) + numaflowClient := dfv1versiond.NewForConfigOrDie(restConfig).NumaflowV1alpha1() + return &handler{ + kubeClient: kubeClient, + metricsClient: metricsClient, + numaflowClient: numaflowClient, + }, nil +} + +func (h *handler) ListPipelines(c *gin.Context) { + plList, err := h.numaflowClient.Pipelines(c.Param("namespace")).List(context.Background(), metav1.ListOptions{}) + if err != nil { + c.JSON(http.StatusInternalServerError, err.Error()) + return + } + c.JSON(http.StatusOK, plList.Items) +} + +func (h *handler) GetPipeline(c *gin.Context) { + pl, err := h.numaflowClient.Pipelines(c.Param("namespace")).Get(context.Background(), c.Param("pipeline"), metav1.GetOptions{}) + if err != nil { + c.JSON(http.StatusInternalServerError, err.Error()) + return + } + c.JSON(http.StatusOK, pl) +} + +func (h *handler) ListNamespaces(c *gin.Context) { + l, err := h.numaflowClient.Pipelines("").List(context.Background(), metav1.ListOptions{}) + if err != nil { + c.JSON(http.StatusInternalServerError, err.Error()) + return + } + m := make(map[string]bool) + for _, pl := range l.Items { + m[pl.Namespace] = true + } + namespaces := []string{} + for k := range m { + namespaces = append(namespaces, k) + } + c.JSON(http.StatusOK, namespaces) +} + +func (h *handler) ListInterStepBufferServices(c *gin.Context) { + limit, _ := strconv.ParseInt(c.Query("limit"), 10, 64) + isbSvcs, err := h.numaflowClient.InterStepBufferServices(c.Param("namespace")).List(context.Background(), metav1.ListOptions{ + Limit: limit, + Continue: c.Query("continue"), + }) + if err != nil { + c.JSON(http.StatusInternalServerError, err.Error()) + return + } + c.JSON(http.StatusOK, isbSvcs.Items) +} + +func (h *handler) GetInterStepBufferService(c *gin.Context) { + isbsvc, err := h.numaflowClient.InterStepBufferServices(c.Param("namespace")).Get(context.Background(), c.Param("isbsvc"), metav1.GetOptions{}) + if err != nil { + c.JSON(http.StatusInternalServerError, err.Error()) + return + } + c.JSON(http.StatusOK, isbsvc) +} + +func (h *handler) ListVerices(c *gin.Context) { + limit, _ := strconv.ParseInt(c.Query("limit"), 10, 64) + vertices, err := h.numaflowClient.Vertices(c.Param("namespace")).List(context.Background(), metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s", dfv1.KeyPipelineName, c.Param("pipeline")), + Limit: limit, + Continue: c.Query("continue"), + }) + if err != nil { + c.JSON(http.StatusInternalServerError, err.Error()) + return + } + c.JSON(http.StatusOK, vertices.Items) +} + +func (h *handler) GetVertex(c *gin.Context) { + vertices, err := h.numaflowClient.Vertices(c.Param("namespace")).List(context.Background(), metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s,%s=%s", dfv1.KeyPipelineName, c.Param("pipeline"), dfv1.KeyVertexName, c.Param("vertex")), + }) + if err != nil { + c.JSON(http.StatusInternalServerError, err.Error()) + return + } + if len(vertices.Items) == 0 { + c.JSON(http.StatusNotFound, fmt.Sprintf("Vertex %q not found", c.Param("vertex"))) + return + } + c.JSON(http.StatusOK, vertices.Items[0]) +} + +func (h *handler) ListVertexPods(c *gin.Context) { + limit, _ := strconv.ParseInt(c.Query("limit"), 10, 64) + pods, err := h.kubeClient.CoreV1().Pods(c.Param("namespace")).List(context.Background(), metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s,%s=%s", dfv1.KeyPipelineName, c.Param("pipeline"), dfv1.KeyVertexName, c.Param("vertex")), + Limit: limit, + Continue: c.Query("continue"), + }) + if err != nil { + c.JSON(http.StatusInternalServerError, err.Error()) + return + } + c.JSON(http.StatusOK, pods.Items) +} + +func (h *handler) ListPodsMetrics(c *gin.Context) { + limit, _ := strconv.ParseInt(c.Query("limit"), 10, 64) + l, err := h.metricsClient.MetricsV1beta1().PodMetricses(c.Param("namespace")).List(context.Background(), metav1.ListOptions{ + Limit: limit, + Continue: c.Query("continue"), + }) + if err != nil { + c.JSON(http.StatusInternalServerError, err.Error()) + return + } + c.JSON(http.StatusOK, l.Items) +} + +func (h *handler) GetPodMetrics(c *gin.Context) { + m, err := h.metricsClient.MetricsV1beta1().PodMetricses(c.Param("namespace")).Get(context.Background(), c.Param("pod"), metav1.GetOptions{}) + if err != nil { + c.JSON(http.StatusInternalServerError, err.Error()) + return + } + c.JSON(http.StatusOK, m) +} + +func (h *handler) PodLogs(c *gin.Context) { + var tailLines *int64 + if v := c.Query("tailLines"); v != "" { + x, _ := strconv.ParseInt(v, 10, 64) + tailLines = pointer.Int64(x) + } + stream, err := h.kubeClient.CoreV1(). + Pods(c.Param("namespace")). + GetLogs(c.Param("pod"), &corev1.PodLogOptions{ + Container: c.Query("container"), + Follow: c.Query("follow") == "true", + TailLines: tailLines, + }).Stream(c) + if err != nil { + c.JSON(http.StatusInternalServerError, err.Error()) + return + } + defer stream.Close() + scanner := bufio.NewScanner(stream) + for scanner.Scan() { + _, _ = c.Writer.Write(scanner.Bytes()) + _, _ = c.Writer.WriteString("\n") + c.Writer.Flush() + } +} + +func (h *handler) ListPipelineEdges(c *gin.Context) { + ns := c.Param("namespace") + pipeline := c.Param("pipeline") + client, err := daemonclient.NewDaemonServiceClient(daemonSvcAddress(ns, pipeline)) + if err != nil { + c.JSON(http.StatusInternalServerError, err.Error()) + return + } + l, err := client.ListPipelineBuffers(context.Background(), pipeline) + if err != nil { + c.JSON(http.StatusInternalServerError, err.Error()) + return + } + c.JSON(http.StatusOK, l) +} + +func (h *handler) GetPipelineEdge(c *gin.Context) { + ns := c.Param("namespace") + pipeline := c.Param("pipeline") + client, err := daemonclient.NewDaemonServiceClient(daemonSvcAddress(ns, pipeline)) + if err != nil { + c.JSON(http.StatusInternalServerError, err.Error()) + return + } + // Assume edge is the buffer name + i, err := client.GetPipelineBuffer(context.Background(), pipeline, c.Param("edge")) + if err != nil { + c.JSON(http.StatusInternalServerError, err.Error()) + return + } + c.JSON(http.StatusOK, i) +} + +func daemonSvcAddress(ns, pipeline string) string { + return fmt.Sprintf("%s.%s.svc.cluster.local:%d", fmt.Sprintf("%s-daemon-svc", pipeline), ns, dfv1.DaemonServicePort) +} diff --git a/server/cmd/main.go b/server/cmd/main.go new file mode 100644 index 0000000000..8727792341 --- /dev/null +++ b/server/cmd/main.go @@ -0,0 +1,59 @@ +package main + +import ( + "crypto/tls" + "net/http" + "strings" + + "github.com/gin-contrib/static" + "github.com/gin-gonic/gin" + + sharedtls "github.com/numaproj/numaflow/pkg/shared/tls" + "github.com/numaproj/numaflow/server/routes" +) + +var ( + rewritePathPrefixes = []string{ + "/namespaces", + } +) + +func main() { + router := gin.New() + router.Use(gin.Logger()) + router.RedirectTrailingSlash = true + router.Use(static.Serve("/", static.LocalFile("./ui/build", true))) + routes.Routes(router) + router.Use(UrlRewrite(router)) + cert, err := sharedtls.GenerateX509KeyPair() + if err != nil { + panic(err) + } + server := http.Server{ + Addr: ":8443", + Handler: router, + TLSConfig: &tls.Config{Certificates: []tls.Certificate{*cert}, MinVersion: tls.VersionTLS12}, + } + if err := server.ListenAndServeTLS("", ""); err != nil { + panic(err) + } +} + +func needToRewrite(path string) bool { + for _, p := range rewritePathPrefixes { + if strings.HasPrefix(path, p) { + return true + } + } + return false +} + +func UrlRewrite(r *gin.Engine) gin.HandlerFunc { + return func(c *gin.Context) { + if needToRewrite(c.Request.URL.Path) { + c.Request.URL.Path = "/" + r.HandleContext(c) + } + c.Next() + } +} diff --git a/server/routes/routes.go b/server/routes/routes.go new file mode 100644 index 0000000000..9e6d6efc07 --- /dev/null +++ b/server/routes/routes.go @@ -0,0 +1,36 @@ +package routes + +import ( + "net/http" + + "github.com/gin-gonic/gin" + + v1 "github.com/numaproj/numaflow/server/apis/v1" +) + +func Routes(r *gin.Engine) { + r.GET("/healthz", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + v1Routes(r.Group("/api/v1")) +} + +func v1Routes(r gin.IRouter) { + handler, err := v1.NewHandler() + if err != nil { + panic(err) + } + r.GET("/namespaces", handler.ListNamespaces) + r.GET("/namespaces/:namespace/pipelines", handler.ListPipelines) + r.GET("/namespaces/:namespace/isbsvcs", handler.ListInterStepBufferServices) + r.GET("/namespaces/:namespace/isbsvcs/:isbsvc", handler.GetInterStepBufferService) + r.GET("/namespaces/:namespace/pipelines/:pipeline", handler.GetPipeline) + r.GET("/namespaces/:namespace/pipelines/:pipeline/vertices", handler.ListVerices) + r.GET("/namespaces/:namespace/pipelines/:pipeline/vertices/:vertex", handler.GetVertex) + r.GET("/namespaces/:namespace/pipelines/:pipeline/vertices/:vertex/pods", handler.ListVertexPods) + r.GET("/namespaces/:namespace/pods/:pod/log", handler.PodLogs) + r.GET("/metrics/namespaces/:namespace/pods", handler.ListPodsMetrics) + r.GET("/metrics/namespaces/:namespace/pods/:pod", handler.GetPodMetrics) + r.GET("/namespaces/:namespace/pipelines/:pipeline/edges", handler.ListPipelineEdges) + r.GET("/namespaces/:namespace/pipelines/:pipeline/edges/:edge", handler.GetPipelineEdge) +} diff --git a/server/routes/routes_test.go b/server/routes/routes_test.go new file mode 100644 index 0000000000..2fd3b57d43 --- /dev/null +++ b/server/routes/routes_test.go @@ -0,0 +1,34 @@ +package routes + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestRoutes(t *testing.T) { + // skipping this test for the time being + t.Skip() + router := gin.Default() + Routes(router) + t.Run("/404", func(t *testing.T) { + w := httptest.NewRecorder() + req, err := http.NewRequest(http.MethodGet, "/404", nil) + require.NoError(t, err) + router.ServeHTTP(w, req) + assert.Equal(t, http.StatusNotFound, w.Code) + }) + + t.Run("/healthz", func(t *testing.T) { + w := httptest.NewRecorder() + req, err := http.NewRequest(http.MethodGet, "/healthz", nil) + require.NoError(t, err) + router.ServeHTTP(w, req) + assert.Equal(t, http.StatusOK, w.Code) + }) + +}