From fbcd3ca806937e07574cf0e656bea4f5c6b65651 Mon Sep 17 00:00:00 2001 From: William Petit Date: Tue, 21 Mar 2023 13:28:41 +0100 Subject: [PATCH] feat: rename gateway spec to proxy --- go.mod | 8 +- go.sum | 18 +-- internal/agent/controller/app/controller.go | 21 ++- internal/agent/controller/app/server.go | 19 ++- .../agent/controller/gateway/controller.go | 124 ------------------ internal/agent/controller/proxy/controller.go | 124 ++++++++++++++++++ .../{gateway => proxy}/reverse_proxy.go | 2 +- internal/command/agent/run.go | 6 +- internal/command/api/agent/spec/update.go | 2 +- internal/command/main.go | 2 +- internal/config/agent.go | 6 +- internal/server/spec_api.go | 2 +- internal/spec/app/schema.json | 9 ++ internal/spec/app/spec.go | 10 +- internal/spec/{gateway => proxy}/init.go | 4 +- internal/spec/{gateway => proxy}/schema.json | 10 +- internal/spec/{gateway => proxy}/spec.go | 16 +-- .../testdata/spec-additional-prop.json | 4 +- .../testdata/spec-missing-prop.json | 4 +- .../{gateway => proxy}/testdata/spec-ok.json | 4 +- .../spec/{gateway => proxy}/validator_test.go | 4 +- 21 files changed, 216 insertions(+), 183 deletions(-) delete mode 100644 internal/agent/controller/gateway/controller.go create mode 100644 internal/agent/controller/proxy/controller.go rename internal/agent/controller/{gateway => proxy}/reverse_proxy.go (98%) rename internal/spec/{gateway => proxy}/init.go (71%) rename internal/spec/{gateway => proxy}/schema.json (77%) rename internal/spec/{gateway => proxy}/spec.go (59%) rename internal/spec/{gateway => proxy}/testdata/spec-additional-prop.json (73%) rename internal/spec/{gateway => proxy}/testdata/spec-missing-prop.json (63%) rename internal/spec/{gateway => proxy}/testdata/spec-ok.json (71%) rename internal/spec/{gateway => proxy}/validator_test.go (94%) diff --git a/go.mod b/go.mod index 18c6a00..ab8af0d 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,13 @@ module forge.cadoles.com/Cadoles/emissary go 1.19 require ( - forge.cadoles.com/arcad/edge v0.0.0-20230310133312-fd12d2ba42fa + forge.cadoles.com/arcad/edge v0.0.0-20230320204239-1f4f795d43ff github.com/alecthomas/participle/v2 v2.0.0-beta.5 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 github.com/btcsuite/btcd/btcutil v1.1.3 github.com/davecgh/go-spew v1.1.1 github.com/denisbrodbeck/machineid v1.0.1 + github.com/dop251/goja v0.0.0-20230304130813-e2f543bf4b4c github.com/evanphx/json-patch/v5 v5.6.0 github.com/go-chi/chi v4.1.2+incompatible github.com/go-chi/cors v1.2.1 @@ -17,6 +18,7 @@ require ( github.com/jedib0t/go-pretty/v6 v6.4.4 github.com/lestrrat-go/jwx/v2 v2.0.8 github.com/lithammer/shortuuid/v4 v4.0.0 + github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/mitchellh/mapstructure v1.5.0 github.com/pkg/errors v0.9.1 github.com/qri-io/jsonschema v0.2.1 @@ -29,7 +31,6 @@ require ( require ( github.com/barnybug/go-cast v0.0.0-20201201064555-a87ccbc26692 // indirect - github.com/dop251/goja v0.0.0-20230304130813-e2f543bf4b4c // indirect github.com/dop251/goja_nodejs v0.0.0-20230226152057-060fa99b809f // indirect github.com/gabriel-vasile/mimetype v1.4.1 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect @@ -40,7 +41,6 @@ require ( github.com/hashicorp/mdns v1.0.5 // indirect github.com/igm/sockjs-go/v3 v3.0.2 // indirect github.com/miekg/dns v1.1.51 // indirect - github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/oklog/ulid/v2 v2.1.0 // indirect github.com/orcaman/concurrent-map v1.0.0 // indirect golang.org/x/net v0.8.0 // indirect @@ -107,3 +107,5 @@ require ( modernc.org/strutil v1.1.3 // indirect modernc.org/token v1.1.0 // indirect ) + +// replace forge.cadoles.com/arcad/edge => ../edge diff --git a/go.sum b/go.sum index 7d5af6e..df179ac 100644 --- a/go.sum +++ b/go.sum @@ -54,10 +54,10 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -forge.cadoles.com/arcad/edge v0.0.0-20230303153719-6399196fe5c9 h1:dleaaf/rV2GWtGvrPunRakjrKVDfXoANxAy8/1ctMVs= -forge.cadoles.com/arcad/edge v0.0.0-20230303153719-6399196fe5c9/go.mod h1:pl9EMtSLSVr4wbDgQBDjr4aizwtmwasE686dm5arYPw= forge.cadoles.com/arcad/edge v0.0.0-20230310133312-fd12d2ba42fa h1:dk0rNaBuCx0SxWTZBodg/y655tBaRtgLcW2hDqZRdxg= forge.cadoles.com/arcad/edge v0.0.0-20230310133312-fd12d2ba42fa/go.mod h1:pl9EMtSLSVr4wbDgQBDjr4aizwtmwasE686dm5arYPw= +forge.cadoles.com/arcad/edge v0.0.0-20230320204239-1f4f795d43ff h1:dT7cZQWzSYfW3dVDOSe6OACBGBQNvn0wo32BIvDEowE= +forge.cadoles.com/arcad/edge v0.0.0-20230320204239-1f4f795d43ff/go.mod h1:ONd6vyQ0IM0vHi1i+bmZBRc1Fd0BoXMuDdY/+0sZefw= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= @@ -448,8 +448,6 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja v0.0.0-20221118162653-d4bf6fde1b86/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= -github.com/dop251/goja v0.0.0-20230226152633-7c93113e17ac h1:NGu46Adk2oPN3tinGFItahy4W9l+9uhEf03ZxbwmdVE= -github.com/dop251/goja v0.0.0-20230226152633-7c93113e17ac/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= github.com/dop251/goja v0.0.0-20230304130813-e2f543bf4b4c h1:/utv6nmTctV6OVgfk5+O6lEMEWL+6KJy4h9NZ5fnkQQ= github.com/dop251/goja v0.0.0-20230304130813-e2f543bf4b4c/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= @@ -696,7 +694,6 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= github.com/google/pprof v0.0.0-20230309165930-d61513b1440d h1:um9/pc7tKMINFfP1eE7Wv6PRGXlcCSJkVajF7KJw3uQ= github.com/google/pprof v0.0.0-20230309165930-d61513b1440d/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= @@ -1028,7 +1025,6 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU= github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= @@ -1389,8 +1385,6 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1519,8 +1513,6 @@ golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1686,8 +1678,6 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1697,8 +1687,6 @@ golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1713,8 +1701,6 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/internal/agent/controller/app/controller.go b/internal/agent/controller/app/controller.go index ad927ff..e8c89da 100644 --- a/internal/agent/controller/app/controller.go +++ b/internal/agent/controller/app/controller.go @@ -11,6 +11,7 @@ import ( "forge.cadoles.com/Cadoles/emissary/internal/spec/app" "forge.cadoles.com/arcad/edge/pkg/bundle" "forge.cadoles.com/arcad/edge/pkg/storage/sqlite" + "github.com/lestrrat-go/jwx/v2/jwk" "github.com/mitchellh/hashstructure/v2" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/logger" @@ -96,18 +97,32 @@ func (c *Controller) updateApps(ctx context.Context, spec *app.Spec) { } } + var ( + key jwk.Key + err error + ) + + if spec.Auth != nil { + key, err = jwk.FromRaw(spec.Auth.Key) + if err != nil { + logger.Error(ctx, "could not parse authentication key", logger.E(errors.WithStack(err))) + + return + } + } + // (Re)start apps for appID, appSpec := range spec.Apps { appCtx := logger.With(ctx, logger.F("appID", appID)) - if err := c.updateApp(ctx, appID, appSpec); err != nil { + if err := c.updateApp(ctx, appID, appSpec, key); err != nil { logger.Error(appCtx, "could not update app", logger.E(errors.WithStack(err))) continue } } } -func (c *Controller) updateApp(ctx context.Context, appID string, appSpec app.AppEntry) (err error) { +func (c *Controller) updateApp(ctx context.Context, appID string, appSpec app.AppEntry, key jwk.Key) (err error) { newAppSpecHash, err := hashstructure.Hash(appSpec, hashstructure.FormatV2, nil) if err != nil { return errors.WithStack(err) @@ -150,7 +165,7 @@ func (c *Controller) updateApp(ctx context.Context, appID string, appSpec app.Ap } entry = &serverEntry{ - Server: NewServer(bundle, db), + Server: NewServer(bundle, db, key), SpecHash: 0, } diff --git a/internal/agent/controller/app/server.go b/internal/agent/controller/app/server.go index cbd84f0..741a8d3 100644 --- a/internal/agent/controller/app/server.go +++ b/internal/agent/controller/app/server.go @@ -22,6 +22,7 @@ import ( "github.com/dop251/goja" "github.com/go-chi/chi/middleware" "github.com/go-chi/chi/v5" + "github.com/lestrrat-go/jwx/v2/jwk" "github.com/pkg/errors" ) @@ -30,6 +31,7 @@ type Server struct { db *sql.DB server *http.Server serverMutex sync.RWMutex + key jwk.Key } func (s *Server) Start(ctx context.Context, addr string) (err error) { @@ -129,7 +131,9 @@ func (s *Server) getAppModules(bus bus.Bus, ds storage.DocumentStore, bs storage module.StoreModuleFactory(ds), module.BlobModuleFactory(bus, bs), module.Extends( - auth.ModuleFactory(), + auth.ModuleFactory( + auth.WithJWT(s.getJWTKeySet), + ), func(o *goja.Object) { if err := o.Set("CLAIM_ROLE", "role"); err != nil { panic(errors.New("could not set 'CLAIM_ROLE' property")) @@ -143,9 +147,20 @@ func (s *Server) getAppModules(bus bus.Bus, ds storage.DocumentStore, bs storage } } -func NewServer(bundle bundle.Bundle, db *sql.DB) *Server { +func (s *Server) getJWTKeySet() (jwk.Set, error) { + set := jwk.NewSet() + + if err := set.AddKey(s.key); err != nil { + return nil, errors.WithStack(err) + } + + return set, nil +} + +func NewServer(bundle bundle.Bundle, db *sql.DB, key jwk.Key) *Server { return &Server{ bundle: bundle, db: db, + key: key, } } diff --git a/internal/agent/controller/gateway/controller.go b/internal/agent/controller/gateway/controller.go deleted file mode 100644 index b3b4982..0000000 --- a/internal/agent/controller/gateway/controller.go +++ /dev/null @@ -1,124 +0,0 @@ -package gateway - -import ( - "context" - - "forge.cadoles.com/Cadoles/emissary/internal/agent" - "forge.cadoles.com/Cadoles/emissary/internal/spec/gateway" - "github.com/pkg/errors" - "gitlab.com/wpetit/goweb/logger" -) - -type Controller struct { - proxies map[gateway.ID]*ReverseProxy - currentSpecRevision int -} - -// Name implements node.Controller. -func (c *Controller) Name() string { - return "gateway-controller" -} - -// Reconcile implements node.Controller. -func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error { - gatewaySpec := gateway.NewSpec() - - if err := state.GetSpec(gateway.NameGateway, gatewaySpec); err != nil { - if errors.Is(err, agent.ErrSpecNotFound) { - logger.Info(ctx, "could not find gateway spec, stopping all remaining proxies") - - c.stopAllProxies(ctx) - - return nil - } - - return errors.WithStack(err) - } - - logger.Info(ctx, "retrieved spec", logger.F("spec", gatewaySpec.SpecName()), logger.F("revision", gatewaySpec.SpecRevision())) - - if c.currentSpecRevision == gatewaySpec.SpecRevision() { - logger.Info(ctx, "spec revision did not change, doing nothing") - - return nil - } - - c.updateProxies(ctx, gatewaySpec) - - c.currentSpecRevision = gatewaySpec.SpecRevision() - logger.Info(ctx, "updating current spec revision", logger.F("revision", c.currentSpecRevision)) - - return nil -} - -func (c *Controller) stopAllProxies(ctx context.Context) { - for gatewayID, proxy := range c.proxies { - logger.Info(ctx, "stopping proxy", logger.F("gatewayID", gatewayID)) - - if err := proxy.Stop(); err != nil { - logger.Error( - ctx, "error while stopping proxy", - logger.F("gatewayID", gatewayID), - logger.E(errors.WithStack(err)), - ) - - delete(c.proxies, gatewayID) - } - } -} - -func (c *Controller) updateProxies(ctx context.Context, spec *gateway.Spec) { - // Stop and remove obsolete gateways - for gatewayID, proxy := range c.proxies { - if _, exists := spec.Gateways[gatewayID]; exists { - continue - } - - logger.Info(ctx, "stopping proxy", logger.F("gatewayID", gatewayID)) - - if err := proxy.Stop(); err != nil { - logger.Error( - ctx, "error while stopping proxy", - logger.F("gatewayID", gatewayID), - logger.E(errors.WithStack(err)), - ) - - delete(c.proxies, gatewayID) - } - } - - // (Re)start gateways - for gatewayID, gatewaySpec := range spec.Gateways { - proxy, exists := c.proxies[gatewayID] - if !exists { - proxy = NewReverseProxy() - c.proxies[gatewayID] = proxy - } - - logger.Info( - ctx, "starting proxy", - logger.F("gatewayID", gatewayID), - logger.F("addr", gatewaySpec.Address), - logger.F("target", gatewaySpec.Target), - ) - - if err := proxy.Start(ctx, gatewaySpec.Address, gatewaySpec.Target); err != nil { - logger.Error( - ctx, "error while starting proxy", - logger.F("gatewayID", gatewayID), - logger.E(errors.WithStack(err)), - ) - - delete(c.proxies, gatewayID) - } - } -} - -func NewController() *Controller { - return &Controller{ - proxies: make(map[gateway.ID]*ReverseProxy), - currentSpecRevision: -1, - } -} - -var _ agent.Controller = &Controller{} diff --git a/internal/agent/controller/proxy/controller.go b/internal/agent/controller/proxy/controller.go new file mode 100644 index 0000000..3dd12a7 --- /dev/null +++ b/internal/agent/controller/proxy/controller.go @@ -0,0 +1,124 @@ +package proxy + +import ( + "context" + + "forge.cadoles.com/Cadoles/emissary/internal/agent" + "forge.cadoles.com/Cadoles/emissary/internal/spec/proxy" + "github.com/pkg/errors" + "gitlab.com/wpetit/goweb/logger" +) + +type Controller struct { + proxies map[proxy.ID]*ReverseProxy + currentSpecRevision int +} + +// Name implements node.Controller. +func (c *Controller) Name() string { + return "proxy-controller" +} + +// Reconcile implements node.Controller. +func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error { + proxySpec := proxy.NewSpec() + + if err := state.GetSpec(proxy.NameProxy, proxySpec); err != nil { + if errors.Is(err, agent.ErrSpecNotFound) { + logger.Info(ctx, "could not find proxy spec, stopping all remaining proxies") + + c.stopAllProxies(ctx) + + return nil + } + + return errors.WithStack(err) + } + + logger.Info(ctx, "retrieved spec", logger.F("spec", proxySpec.SpecName()), logger.F("revision", proxySpec.SpecRevision())) + + if c.currentSpecRevision == proxySpec.SpecRevision() { + logger.Info(ctx, "spec revision did not change, doing nothing") + + return nil + } + + c.updateProxies(ctx, proxySpec) + + c.currentSpecRevision = proxySpec.SpecRevision() + logger.Info(ctx, "updating current spec revision", logger.F("revision", c.currentSpecRevision)) + + return nil +} + +func (c *Controller) stopAllProxies(ctx context.Context) { + for proxyID, proxy := range c.proxies { + logger.Info(ctx, "stopping proxy", logger.F("proxyID", proxyID)) + + if err := proxy.Stop(); err != nil { + logger.Error( + ctx, "error while stopping proxy", + logger.F("proxyID", proxyID), + logger.E(errors.WithStack(err)), + ) + + delete(c.proxies, proxyID) + } + } +} + +func (c *Controller) updateProxies(ctx context.Context, spec *proxy.Spec) { + // Stop and remove obsolete proxys + for proxyID, proxy := range c.proxies { + if _, exists := spec.Proxies[proxyID]; exists { + continue + } + + logger.Info(ctx, "stopping proxy", logger.F("proxyID", proxyID)) + + if err := proxy.Stop(); err != nil { + logger.Error( + ctx, "error while stopping proxy", + logger.F("proxyID", proxyID), + logger.E(errors.WithStack(err)), + ) + + delete(c.proxies, proxyID) + } + } + + // (Re)start proxys + for proxyID, proxySpec := range spec.Proxies { + proxy, exists := c.proxies[proxyID] + if !exists { + proxy = NewReverseProxy() + c.proxies[proxyID] = proxy + } + + logger.Info( + ctx, "starting proxy", + logger.F("proxyID", proxyID), + logger.F("addr", proxySpec.Address), + logger.F("target", proxySpec.Target), + ) + + if err := proxy.Start(ctx, proxySpec.Address, proxySpec.Target); err != nil { + logger.Error( + ctx, "error while starting proxy", + logger.F("proxyID", proxyID), + logger.E(errors.WithStack(err)), + ) + + delete(c.proxies, proxyID) + } + } +} + +func NewController() *Controller { + return &Controller{ + proxies: make(map[proxy.ID]*ReverseProxy), + currentSpecRevision: -1, + } +} + +var _ agent.Controller = &Controller{} diff --git a/internal/agent/controller/gateway/reverse_proxy.go b/internal/agent/controller/proxy/reverse_proxy.go similarity index 98% rename from internal/agent/controller/gateway/reverse_proxy.go rename to internal/agent/controller/proxy/reverse_proxy.go index 0113d54..2935f1b 100644 --- a/internal/agent/controller/gateway/reverse_proxy.go +++ b/internal/agent/controller/proxy/reverse_proxy.go @@ -1,4 +1,4 @@ -package gateway +package proxy import ( "context" diff --git a/internal/command/agent/run.go b/internal/command/agent/run.go index c01edc4..a48bd2c 100644 --- a/internal/command/agent/run.go +++ b/internal/command/agent/run.go @@ -5,9 +5,9 @@ import ( "forge.cadoles.com/Cadoles/emissary/internal/agent" "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app" - "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/gateway" "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/openwrt" "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/persistence" + "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/proxy" "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/spec" "forge.cadoles.com/Cadoles/emissary/internal/agent/metadata" "forge.cadoles.com/Cadoles/emissary/internal/agent/metadata/collector/buildinfo" @@ -49,8 +49,8 @@ func RunCommand() *cli.Command { controllers = append(controllers, spec.NewController()) } - if ctrlConf.Gateway.Enabled { - controllers = append(controllers, gateway.NewController()) + if ctrlConf.Proxy.Enabled { + controllers = append(controllers, proxy.NewController()) } if ctrlConf.UCI.Enabled { diff --git a/internal/command/api/agent/spec/update.go b/internal/command/api/agent/spec/update.go index 31eef5c..f752e31 100644 --- a/internal/command/api/agent/spec/update.go +++ b/internal/command/api/agent/spec/update.go @@ -16,7 +16,7 @@ import ( // Import specs _ "forge.cadoles.com/Cadoles/emissary/internal/spec/app" - _ "forge.cadoles.com/Cadoles/emissary/internal/spec/gateway" + _ "forge.cadoles.com/Cadoles/emissary/internal/spec/proxy" _ "forge.cadoles.com/Cadoles/emissary/internal/spec/uci" ) diff --git a/internal/command/main.go b/internal/command/main.go index de9c4f2..0e05e19 100644 --- a/internal/command/main.go +++ b/internal/command/main.go @@ -11,7 +11,7 @@ import ( "github.com/urfave/cli/v2" // Spec validation - _ "forge.cadoles.com/Cadoles/emissary/internal/spec/gateway" + _ "forge.cadoles.com/Cadoles/emissary/internal/spec/proxy" _ "forge.cadoles.com/Cadoles/emissary/internal/spec/uci" ) diff --git a/internal/config/agent.go b/internal/config/agent.go index 9dfbe38..7d7edd7 100644 --- a/internal/config/agent.go +++ b/internal/config/agent.go @@ -17,7 +17,7 @@ type ShellCollectorConfig struct { type ControllersConfig struct { Persistence PersistenceControllerConfig `yaml:"persistence"` Spec SpecControllerConfig `yaml:"spec"` - Gateway GatewayControllerConfig `yaml:"gateway"` + Proxy ProxyControllerConfig `yaml:"proxy"` UCI UCIControllerConfig `yaml:"uci"` App AppControllerConfig `yaml:"app"` } @@ -30,7 +30,7 @@ type PersistenceControllerConfig struct { type SpecControllerConfig struct { Enabled InterpolatedBool `yaml:"enabled"` } -type GatewayControllerConfig struct { +type ProxyControllerConfig struct { Enabled InterpolatedBool `yaml:"enabled"` } @@ -59,7 +59,7 @@ func NewDefaultAgentConfig() AgentConfig { Enabled: true, StateFile: "state.json", }, - Gateway: GatewayControllerConfig{ + Proxy: ProxyControllerConfig{ Enabled: true, }, UCI: UCIControllerConfig{ diff --git a/internal/server/spec_api.go b/internal/server/spec_api.go index c1de1a2..b2c90b9 100644 --- a/internal/server/spec_api.go +++ b/internal/server/spec_api.go @@ -13,7 +13,7 @@ import ( // Import specs _ "forge.cadoles.com/Cadoles/emissary/internal/spec/app" - _ "forge.cadoles.com/Cadoles/emissary/internal/spec/gateway" + _ "forge.cadoles.com/Cadoles/emissary/internal/spec/proxy" _ "forge.cadoles.com/Cadoles/emissary/internal/spec/uci" ) diff --git a/internal/spec/app/schema.json b/internal/spec/app/schema.json index 694c656..4ae2e20 100644 --- a/internal/spec/app/schema.json +++ b/internal/spec/app/schema.json @@ -29,6 +29,15 @@ "additionalProperties": false } } + }, + "auth": { + "type": "object", + "properties": { + "key": { + "type": "object" + } + }, + "required": ["key"] } }, "required": ["apps"], diff --git a/internal/spec/app/spec.go b/internal/spec/app/spec.go index 4e24199..82173b6 100644 --- a/internal/spec/app/spec.go +++ b/internal/spec/app/spec.go @@ -7,8 +7,9 @@ import ( const NameApp spec.Name = "app.emissary.cadoles.com" type Spec struct { - Revision int `json:"revisions"` - Apps map[string]AppEntry + Revision int `json:"revisions"` + Apps map[string]AppEntry `json:"apps"` + Auth *Auth `json:"auth"` } type AppEntry struct { @@ -18,6 +19,10 @@ type AppEntry struct { Format string `json:"format"` } +type Auth struct { + Key any `json:"key"` +} + func (s *Spec) SpecName() spec.Name { return NameApp } @@ -29,6 +34,7 @@ func (s *Spec) SpecRevision() int { func (s *Spec) SpecData() map[string]any { return map[string]any{ "apps": s.Apps, + "auth": s.Auth, } } diff --git a/internal/spec/gateway/init.go b/internal/spec/proxy/init.go similarity index 71% rename from internal/spec/gateway/init.go rename to internal/spec/proxy/init.go index af01b4d..2f0759c 100644 --- a/internal/spec/gateway/init.go +++ b/internal/spec/proxy/init.go @@ -1,4 +1,4 @@ -package gateway +package proxy import ( _ "embed" @@ -11,7 +11,7 @@ import ( var schema []byte func init() { - if err := spec.Register(NameGateway, schema); err != nil { + if err := spec.Register(NameProxy, schema); err != nil { panic(errors.WithStack(err)) } } diff --git a/internal/spec/gateway/schema.json b/internal/spec/proxy/schema.json similarity index 77% rename from internal/spec/gateway/schema.json rename to internal/spec/proxy/schema.json index d307067..c96809c 100644 --- a/internal/spec/gateway/schema.json +++ b/internal/spec/proxy/schema.json @@ -1,11 +1,11 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://gateway.emissary.cadoles.com/spec.json", - "title": "GatewaySpec", - "description": "Emissary 'Gateway' specification", + "$id": "https://proxy.emissary.cadoles.com/spec.json", + "title": "ProxySpec", + "description": "Emissary 'Proxy' specification", "type": "object", "properties": { - "gateways": { + "proxies": { "type": "object", "patternProperties": { ".*": { @@ -24,6 +24,6 @@ } } }, - "required": ["gateways"], + "required": ["proxies"], "additionalProperties": false } \ No newline at end of file diff --git a/internal/spec/gateway/spec.go b/internal/spec/proxy/spec.go similarity index 59% rename from internal/spec/gateway/spec.go rename to internal/spec/proxy/spec.go index 82651f0..d5c9ebc 100644 --- a/internal/spec/gateway/spec.go +++ b/internal/spec/proxy/spec.go @@ -1,23 +1,23 @@ -package gateway +package proxy import "forge.cadoles.com/Cadoles/emissary/internal/spec" -const NameGateway spec.Name = "gateway.emissary.cadoles.com" +const NameProxy spec.Name = "proxy.emissary.cadoles.com" type ID string type Spec struct { - Revision int `json:"revision"` - Gateways map[ID]GatewayEntry `json:"gateways"` + Revision int `json:"revision"` + Proxies map[ID]ProxyEntry `json:"proxies"` } -type GatewayEntry struct { +type ProxyEntry struct { Address string `json:"address"` Target string `json:"target"` } func (s *Spec) SpecName() spec.Name { - return NameGateway + return NameProxy } func (s *Spec) SpecRevision() int { @@ -26,14 +26,14 @@ func (s *Spec) SpecRevision() int { func (s *Spec) SpecData() map[string]any { return map[string]any{ - "gateways": s.Gateways, + "proxies": s.Proxies, } } func NewSpec() *Spec { return &Spec{ Revision: -1, - Gateways: make(map[ID]GatewayEntry), + Proxies: make(map[ID]ProxyEntry), } } diff --git a/internal/spec/gateway/testdata/spec-additional-prop.json b/internal/spec/proxy/testdata/spec-additional-prop.json similarity index 73% rename from internal/spec/gateway/testdata/spec-additional-prop.json rename to internal/spec/proxy/testdata/spec-additional-prop.json index 7f40339..1c3edf7 100644 --- a/internal/spec/gateway/testdata/spec-additional-prop.json +++ b/internal/spec/proxy/testdata/spec-additional-prop.json @@ -1,7 +1,7 @@ { - "name": "gateway.emissary.cadoles.com", + "name": "proxy.emissary.cadoles.com", "data": { - "gateways": { + "proxies": { "cadoles.com": { "address": ":3003", "target": "https://www.cadoles.com", diff --git a/internal/spec/gateway/testdata/spec-missing-prop.json b/internal/spec/proxy/testdata/spec-missing-prop.json similarity index 63% rename from internal/spec/gateway/testdata/spec-missing-prop.json rename to internal/spec/proxy/testdata/spec-missing-prop.json index 623e027..4733a3e 100644 --- a/internal/spec/gateway/testdata/spec-missing-prop.json +++ b/internal/spec/proxy/testdata/spec-missing-prop.json @@ -1,7 +1,7 @@ { - "name": "gateway.emissary.cadoles.com", + "name": "proxy.emissary.cadoles.com", "data": { - "gateways": { + "proxies": { "cadoles.com": { "address": ":3003" } diff --git a/internal/spec/gateway/testdata/spec-ok.json b/internal/spec/proxy/testdata/spec-ok.json similarity index 71% rename from internal/spec/gateway/testdata/spec-ok.json rename to internal/spec/proxy/testdata/spec-ok.json index 1cd94c8..0009c7f 100644 --- a/internal/spec/gateway/testdata/spec-ok.json +++ b/internal/spec/proxy/testdata/spec-ok.json @@ -1,7 +1,7 @@ { - "name": "gateway.emissary.cadoles.com", + "name": "proxy.emissary.cadoles.com", "data": { - "gateways": { + "proxies": { "cadoles.com": { "address": ":3003", "target": "https://www.cadoles.com" diff --git a/internal/spec/gateway/validator_test.go b/internal/spec/proxy/validator_test.go similarity index 94% rename from internal/spec/gateway/validator_test.go rename to internal/spec/proxy/validator_test.go index 634819b..bf80291 100644 --- a/internal/spec/gateway/validator_test.go +++ b/internal/spec/proxy/validator_test.go @@ -1,4 +1,4 @@ -package gateway +package proxy import ( "context" @@ -38,7 +38,7 @@ func TestValidator(t *testing.T) { t.Parallel() validator := spec.NewValidator() - if err := validator.Register(NameGateway, schema); err != nil { + if err := validator.Register(NameProxy, schema); err != nil { t.Fatalf("+%v", errors.WithStack(err)) }