feat: add mdns controller
arcad/emissary/pipeline/head There was a failure building this commit
Details
arcad/emissary/pipeline/head There was a failure building this commit
Details
This commit is contained in:
parent
562d698066
commit
242a247222
1
Makefile
1
Makefile
|
@ -151,6 +151,7 @@ AGENT_ID ?= 1
|
||||||
load-sample-specs:
|
load-sample-specs:
|
||||||
cat misc/spec-samples/app.emissary.cadoles.com.json | ./bin/server api agent spec update -a $(AGENT_ID) --no-patch --spec-data - --spec-name app.emissary.cadoles.com
|
cat misc/spec-samples/app.emissary.cadoles.com.json | ./bin/server api agent spec update -a $(AGENT_ID) --no-patch --spec-data - --spec-name app.emissary.cadoles.com
|
||||||
cat misc/spec-samples/proxy.emissary.cadoles.com.json | ./bin/server api agent spec update -a $(AGENT_ID) --no-patch --spec-data - --spec-name proxy.emissary.cadoles.com
|
cat misc/spec-samples/proxy.emissary.cadoles.com.json | ./bin/server api agent spec update -a $(AGENT_ID) --no-patch --spec-data - --spec-name proxy.emissary.cadoles.com
|
||||||
|
cat misc/spec-samples/mdns.emissary.cadoles.com.json | ./bin/server api agent spec update -a $(AGENT_ID) --no-patch --spec-data - --spec-name mdns.emissary.cadoles.com
|
||||||
|
|
||||||
full-version:
|
full-version:
|
||||||
@echo $(FULL_VERSION)
|
@echo $(FULL_VERSION)
|
1
go.mod
1
go.mod
|
@ -33,6 +33,7 @@ require (
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
||||||
github.com/barnybug/go-cast v0.0.0-20201201064555-a87ccbc26692 // indirect
|
github.com/barnybug/go-cast v0.0.0-20201201064555-a87ccbc26692 // indirect
|
||||||
|
github.com/brutella/dnssd v1.2.6 // indirect
|
||||||
github.com/dop251/goja_nodejs v0.0.0-20230320130059-dcf93ba651dd // indirect
|
github.com/dop251/goja_nodejs v0.0.0-20230320130059-dcf93ba651dd // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.1 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.1 // indirect
|
||||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
||||||
|
|
5
go.sum
5
go.sum
|
@ -203,6 +203,8 @@ github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb
|
||||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||||
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
|
github.com/brutella/dnssd v1.2.6 h1:/0P13JkHLRzeLQkWRPEn4hJCr4T3NfknIFw3aNPIC34=
|
||||||
|
github.com/brutella/dnssd v1.2.6/go.mod h1:JoW2sJUrmVIef25G6lrLj7HS6Xdwh6q8WUIvMkkBYXs=
|
||||||
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
|
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
|
||||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||||
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
|
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
|
||||||
|
@ -980,6 +982,7 @@ github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88J
|
||||||
github.com/miekg/dns v0.0.0-20161006100029-fc4e1e2843d8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v0.0.0-20161006100029-fc4e1e2843d8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||||
|
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||||
github.com/miekg/dns v1.1.51 h1:0+Xg7vObnhrz/4ZCZcZh7zPXlmU0aveS2HDBd0m0qSo=
|
github.com/miekg/dns v1.1.51 h1:0+Xg7vObnhrz/4ZCZcZh7zPXlmU0aveS2HDBd0m0qSo=
|
||||||
github.com/miekg/dns v1.1.51/go.mod h1:2Z9d3CP1LQWihRZUf29mQ19yDThaI4DAYzte2CaQW5c=
|
github.com/miekg/dns v1.1.51/go.mod h1:2Z9d3CP1LQWihRZUf29mQ19yDThaI4DAYzte2CaQW5c=
|
||||||
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||||
|
@ -1515,6 +1518,7 @@ golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
@ -1805,6 +1809,7 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
||||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||||
|
|
|
@ -0,0 +1,181 @@
|
||||||
|
package mdns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"forge.cadoles.com/Cadoles/emissary/internal/agent"
|
||||||
|
mdns "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/mdns/spec"
|
||||||
|
"github.com/brutella/dnssd"
|
||||||
|
"github.com/mitchellh/hashstructure/v2"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gitlab.com/wpetit/goweb/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultDomain = "local"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Controller struct {
|
||||||
|
serviceDefHash uint64
|
||||||
|
cancel context.CancelFunc
|
||||||
|
responder dnssd.Responder
|
||||||
|
mutex sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements node.Controller.
|
||||||
|
func (c *Controller) Name() string {
|
||||||
|
return "mdns-controller"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconcile implements node.Controller.
|
||||||
|
func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error {
|
||||||
|
mdnsSpec := mdns.NewSpec()
|
||||||
|
|
||||||
|
if err := state.GetSpec(mdns.Name, mdnsSpec); err != nil {
|
||||||
|
if errors.Is(err, agent.ErrSpecNotFound) {
|
||||||
|
logger.Info(ctx, "could not find mdns spec")
|
||||||
|
|
||||||
|
c.stopResponder(ctx)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info(ctx, "retrieved spec", logger.F("spec", mdnsSpec.SpecName()), logger.F("revision", mdnsSpec.SpecRevision()))
|
||||||
|
|
||||||
|
if err := c.updateResponder(ctx, mdnsSpec); err != nil {
|
||||||
|
return errors.Wrap(err, "could not update responder")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) stopResponder(ctx context.Context) {
|
||||||
|
c.mutex.Lock()
|
||||||
|
defer c.mutex.Unlock()
|
||||||
|
|
||||||
|
if c.responder == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.cancel()
|
||||||
|
c.responder = nil
|
||||||
|
c.cancel = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) updateResponder(ctx context.Context, spec *mdns.Spec) error {
|
||||||
|
serviceDef := struct {
|
||||||
|
Services map[string]mdns.Service
|
||||||
|
}{
|
||||||
|
Services: spec.Services,
|
||||||
|
}
|
||||||
|
|
||||||
|
newServerDefHash, err := hashstructure.Hash(serviceDef, hashstructure.FormatV2, nil)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.mutex.RLock()
|
||||||
|
if newServerDefHash == c.serviceDefHash && c.responder != nil {
|
||||||
|
c.mutex.RUnlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
c.mutex.RUnlock()
|
||||||
|
|
||||||
|
c.stopResponder(ctx)
|
||||||
|
|
||||||
|
defaultIfaces, err := c.getDefaultIfaces()
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
services := make([]dnssd.Service, 0, len(spec.Services))
|
||||||
|
|
||||||
|
for name, service := range spec.Services {
|
||||||
|
domain := service.Domain
|
||||||
|
if domain == "" {
|
||||||
|
domain = DefaultDomain
|
||||||
|
}
|
||||||
|
|
||||||
|
ifaces := service.Ifaces
|
||||||
|
if len(ifaces) == 0 {
|
||||||
|
ifaces = defaultIfaces
|
||||||
|
}
|
||||||
|
|
||||||
|
config := dnssd.Config{
|
||||||
|
Name: name,
|
||||||
|
Type: service.Type,
|
||||||
|
Domain: domain,
|
||||||
|
Host: service.Host,
|
||||||
|
Ifaces: ifaces,
|
||||||
|
Port: service.Port,
|
||||||
|
}
|
||||||
|
|
||||||
|
service, err := dnssd.NewService(config)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(ctx, "could not create mdns service", logger.E(errors.WithStack(err)))
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
services = append(services, service)
|
||||||
|
}
|
||||||
|
|
||||||
|
responder, err := dnssd.NewResponder()
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, service := range services {
|
||||||
|
if _, err := responder.Add(service); err != nil {
|
||||||
|
logger.Error(ctx, "could not add mdns service", logger.E(errors.WithStack(err)))
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
c.responder = responder
|
||||||
|
c.cancel = cancel
|
||||||
|
c.serviceDefHash = newServerDefHash
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer c.stopResponder(ctx)
|
||||||
|
|
||||||
|
if err := responder.Respond(ctx); err != nil && !errors.Is(err, context.Canceled) {
|
||||||
|
logger.Error(ctx, "could not respond to mdns queries", logger.E(errors.WithStack(err)))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) getDefaultIfaces() ([]string, error) {
|
||||||
|
ifaces, err := net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ifaceNames := make([]string, len(ifaces))
|
||||||
|
|
||||||
|
for idx, ifa := range ifaces {
|
||||||
|
ifaceNames[idx] = ifa.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
return ifaceNames, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewController() *Controller {
|
||||||
|
return &Controller{
|
||||||
|
cancel: nil,
|
||||||
|
responder: nil,
|
||||||
|
serviceDefHash: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ agent.Controller = &Controller{}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
|
||||||
|
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed schema.json
|
||||||
|
var schema []byte
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if err := spec.Register(Name, schema); err != nil {
|
||||||
|
panic(errors.WithStack(err))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://mdns.edge.emissary.cadoles.com/spec.json",
|
||||||
|
"title": "MDNSSpec",
|
||||||
|
"description": "Emissary 'MDNS' specification",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"services": {
|
||||||
|
"type": "object",
|
||||||
|
"patternProperties": {
|
||||||
|
".*": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"domain": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ifaces": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"host",
|
||||||
|
"port"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"services"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
||||||
|
)
|
||||||
|
|
||||||
|
const Name spec.Name = "mdns.emissary.cadoles.com"
|
||||||
|
|
||||||
|
type Spec struct {
|
||||||
|
Revision int `json:"revision"`
|
||||||
|
Services map[string]Service `json:"services"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
Ifaces []string `json:"ifaces"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Spec) SpecName() spec.Name {
|
||||||
|
return Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Spec) SpecRevision() int {
|
||||||
|
return s.Revision
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Spec) SpecData() map[string]any {
|
||||||
|
return map[string]any{
|
||||||
|
"services": s.Services,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSpec() *Spec {
|
||||||
|
return &Spec{
|
||||||
|
Revision: -1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ spec.Spec = &Spec{}
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"name": "mdns.emissary.cadoles.com",
|
||||||
|
"data": {
|
||||||
|
"services": {
|
||||||
|
"My Website": {
|
||||||
|
"type": "_http._tcp",
|
||||||
|
"domain": "local",
|
||||||
|
"host": "mywebsite",
|
||||||
|
"ifaces": ["lo", "eth0"],
|
||||||
|
"port": 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"revision": 0
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type validatorTestCase struct {
|
||||||
|
Name string
|
||||||
|
Source string
|
||||||
|
ShouldFail bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var validatorTestCases = []validatorTestCase{
|
||||||
|
{
|
||||||
|
Name: "SpecOK",
|
||||||
|
Source: "testdata/spec-ok.json",
|
||||||
|
ShouldFail: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidator(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
validator := spec.NewValidator()
|
||||||
|
if err := validator.Register(Name, schema); err != nil {
|
||||||
|
t.Fatalf("+%v", errors.WithStack(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range validatorTestCases {
|
||||||
|
func(tc validatorTestCase) {
|
||||||
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
rawSpec, err := ioutil.ReadFile(tc.Source)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("+%v", errors.WithStack(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
var spec spec.RawSpec
|
||||||
|
|
||||||
|
if err := json.Unmarshal(rawSpec, &spec); err != nil {
|
||||||
|
t.Fatalf("+%v", errors.WithStack(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
err = validator.Validate(ctx, &spec)
|
||||||
|
|
||||||
|
if !tc.ShouldFail && err != nil {
|
||||||
|
t.Errorf("+%v", errors.WithStack(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.ShouldFail && err == nil {
|
||||||
|
t.Error("validation should have failed")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}(tc)
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/agent"
|
"forge.cadoles.com/Cadoles/emissary/internal/agent"
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app"
|
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app"
|
||||||
|
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/mdns"
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/openwrt"
|
"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/persistence"
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/proxy"
|
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/proxy"
|
||||||
|
@ -66,6 +67,10 @@ func RunCommand() *cli.Command {
|
||||||
controllers = append(controllers, proxy.NewController())
|
controllers = append(controllers, proxy.NewController())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ctrlConf.MDNS.Enabled {
|
||||||
|
controllers = append(controllers, mdns.NewController())
|
||||||
|
}
|
||||||
|
|
||||||
if ctrlConf.SysUpgrade.Enabled {
|
if ctrlConf.SysUpgrade.Enabled {
|
||||||
sysUpgradeArgs := make([]string, 0)
|
sysUpgradeArgs := make([]string, 0)
|
||||||
if len(ctrlConf.SysUpgrade.SysUpgradeCommand) > 1 {
|
if len(ctrlConf.SysUpgrade.SysUpgradeCommand) > 1 {
|
||||||
|
|
|
@ -23,6 +23,7 @@ type ControllersConfig struct {
|
||||||
UCI UCIControllerConfig `yaml:"uci"`
|
UCI UCIControllerConfig `yaml:"uci"`
|
||||||
App AppControllerConfig `yaml:"app"`
|
App AppControllerConfig `yaml:"app"`
|
||||||
SysUpgrade SysUpgradeControllerConfig `yaml:"sysupgrade"`
|
SysUpgrade SysUpgradeControllerConfig `yaml:"sysupgrade"`
|
||||||
|
MDNS MDNSControllerConfig `yaml:"mdns"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PersistenceControllerConfig struct {
|
type PersistenceControllerConfig struct {
|
||||||
|
@ -55,6 +56,10 @@ type SysUpgradeControllerConfig struct {
|
||||||
FirmwareVersionCommand InterpolatedStringSlice `yaml:"firmwareVersionCommand"`
|
FirmwareVersionCommand InterpolatedStringSlice `yaml:"firmwareVersionCommand"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MDNSControllerConfig struct {
|
||||||
|
Enabled InterpolatedBool `yaml:"enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
func NewDefaultAgentConfig() AgentConfig {
|
func NewDefaultAgentConfig() AgentConfig {
|
||||||
return AgentConfig{
|
return AgentConfig{
|
||||||
ServerURL: "http://127.0.0.1:3000",
|
ServerURL: "http://127.0.0.1:3000",
|
||||||
|
@ -86,6 +91,9 @@ func NewDefaultAgentConfig() AgentConfig {
|
||||||
SysUpgradeCommand: InterpolatedStringSlice{"sysupgrade", "--force", "-u", "-v", openwrt.FirmwareFileTemplate},
|
SysUpgradeCommand: InterpolatedStringSlice{"sysupgrade", "--force", "-u", "-v", openwrt.FirmwareFileTemplate},
|
||||||
FirmwareVersionCommand: InterpolatedStringSlice{"sh", "-c", `source /etc/openwrt_release && echo "$DISTRIB_ID-$DISTRIB_RELEASE-$DISTRIB_REVISION"`},
|
FirmwareVersionCommand: InterpolatedStringSlice{"sh", "-c", `source /etc/openwrt_release && echo "$DISTRIB_ID-$DISTRIB_RELEASE-$DISTRIB_REVISION"`},
|
||||||
},
|
},
|
||||||
|
MDNS: MDNSControllerConfig{
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Collectors: []ShellCollectorConfig{
|
Collectors: []ShellCollectorConfig{
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,7 @@ package spec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec"
|
_ "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec"
|
||||||
|
_ "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/mdns/spec"
|
||||||
_ "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/openwrt/spec/sysupgrade"
|
_ "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/openwrt/spec/sysupgrade"
|
||||||
_ "forge.cadoles.com/Cadoles/emissary/internal/spec/proxy"
|
_ "forge.cadoles.com/Cadoles/emissary/internal/spec/proxy"
|
||||||
_ "forge.cadoles.com/Cadoles/emissary/internal/spec/uci"
|
_ "forge.cadoles.com/Cadoles/emissary/internal/spec/uci"
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"services": {
|
||||||
|
"arcad": {
|
||||||
|
"type": "_http._tcp",
|
||||||
|
"port": 8080,
|
||||||
|
"host": "arcad",
|
||||||
|
"ifaces": ["wlp4s0"]
|
||||||
|
},
|
||||||
|
"portal": {
|
||||||
|
"type": "_http._tcp",
|
||||||
|
"port": 8080,
|
||||||
|
"host": "portal",
|
||||||
|
"domain": "arcad.local",
|
||||||
|
"ifaces": ["wlp4s0"]
|
||||||
|
},
|
||||||
|
"hextris": {
|
||||||
|
"type": "_http._tcp",
|
||||||
|
"port": 8080,
|
||||||
|
"host": "hextris",
|
||||||
|
"domain": "arcad.local",
|
||||||
|
"ifaces": ["wlp4s0"]
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"type": "_http._tcp",
|
||||||
|
"port": 8080,
|
||||||
|
"host": "test",
|
||||||
|
"domain": "arcad.local",
|
||||||
|
"ifaces": ["wlp4s0"]
|
||||||
|
},
|
||||||
|
"diffusion": {
|
||||||
|
"type": "_http._tcp",
|
||||||
|
"port": 8080,
|
||||||
|
"host": "diffusion",
|
||||||
|
"domain": "arcad.local",
|
||||||
|
"ifaces": ["wlp4s0"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,22 @@
|
||||||
"hostPattern": "diffusion.arcad.local:*",
|
"hostPattern": "diffusion.arcad.local:*",
|
||||||
"target": "http://localhost:8085"
|
"target": "http://localhost:8085"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"hostPattern": "arcad-portal.local:*",
|
||||||
|
"target": "http://localhost:8082"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hostPattern": "arcad-hextris.local:*",
|
||||||
|
"target": "http://localhost:8083"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hostPattern": "arcad-test.local:*",
|
||||||
|
"target": "http://localhost:8084"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hostPattern": "arcad-diffusion.local:*",
|
||||||
|
"target": "http://localhost:8085"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"hostPattern": "*",
|
"hostPattern": "*",
|
||||||
"target": "http://localhost:8082"
|
"target": "http://localhost:8082"
|
||||||
|
|
Loading…
Reference in New Issue