feat(controller,app): add app module
This commit is contained in:
parent
3d0b0102c2
commit
e832b7dedd
8
Makefile
8
Makefile
|
@ -144,4 +144,10 @@ tools/gitea-release/bin/gitea-release.sh:
|
||||||
chmod +x tools/gitea-release/bin/gitea-release.sh
|
chmod +x tools/gitea-release/bin/gitea-release.sh
|
||||||
|
|
||||||
.emissary-token:
|
.emissary-token:
|
||||||
$(MAKE) run-emissary-server EMISSARY_CMD="--debug --config tmp/server.yml server auth create-token --role writer > .emissary-token"
|
$(MAKE) run-emissary-server EMISSARY_CMD="--debug --config tmp/server.yml server auth create-token --role writer > .emissary-token"
|
||||||
|
|
||||||
|
AGENT_ID ?= 1
|
||||||
|
|
||||||
|
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/proxy.emissary.cadoles.com.json | ./bin/server api agent spec update -a $(AGENT_ID) --no-patch --spec-data - --spec-name proxy.emissary.cadoles.com
|
11
go.mod
11
go.mod
|
@ -3,7 +3,7 @@ module forge.cadoles.com/Cadoles/emissary
|
||||||
go 1.19
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
forge.cadoles.com/arcad/edge v0.0.0-20230322170544-cf8a3f8ac077
|
forge.cadoles.com/arcad/edge v0.0.0-20230328183829-d8ce2901d2ab
|
||||||
github.com/alecthomas/participle/v2 v2.0.0-beta.5
|
github.com/alecthomas/participle/v2 v2.0.0-beta.5
|
||||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883
|
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883
|
||||||
github.com/btcsuite/btcd/btcutil v1.1.3
|
github.com/btcsuite/btcd/btcutil v1.1.3
|
||||||
|
@ -29,6 +29,9 @@ require (
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
|
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
||||||
|
github.com/Masterminds/sprig/v3 v3.2.3 // 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/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
|
||||||
|
@ -37,10 +40,16 @@ require (
|
||||||
github.com/google/pprof v0.0.0-20230309165930-d61513b1440d // indirect
|
github.com/google/pprof v0.0.0-20230309165930-d61513b1440d // indirect
|
||||||
github.com/gorilla/websocket v1.5.0 // indirect
|
github.com/gorilla/websocket v1.5.0 // indirect
|
||||||
github.com/hashicorp/mdns v1.0.5 // indirect
|
github.com/hashicorp/mdns v1.0.5 // indirect
|
||||||
|
github.com/huandu/xstrings v1.3.3 // indirect
|
||||||
github.com/igm/sockjs-go/v3 v3.0.2 // indirect
|
github.com/igm/sockjs-go/v3 v3.0.2 // indirect
|
||||||
|
github.com/imdario/mergo v0.3.12 // indirect
|
||||||
github.com/miekg/dns v1.1.51 // indirect
|
github.com/miekg/dns v1.1.51 // indirect
|
||||||
|
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||||
github.com/oklog/ulid/v2 v2.1.0 // indirect
|
github.com/oklog/ulid/v2 v2.1.0 // indirect
|
||||||
github.com/orcaman/concurrent-map v1.0.0 // indirect
|
github.com/orcaman/concurrent-map v1.0.0 // indirect
|
||||||
|
github.com/shopspring/decimal v1.2.0 // indirect
|
||||||
|
github.com/spf13/cast v1.3.1 // indirect
|
||||||
golang.org/x/net v0.8.0 // indirect
|
golang.org/x/net v0.8.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20220728213248-dd149ef739b9 // indirect
|
google.golang.org/genproto v0.0.0-20220728213248-dd149ef739b9 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
|
21
go.sum
21
go.sum
|
@ -56,6 +56,10 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
forge.cadoles.com/arcad/edge v0.0.0-20230322170544-cf8a3f8ac077 h1:vsYcNHZevZrs0VeOTasvJoqvPynb8OvH+MMpIUvNT6Q=
|
forge.cadoles.com/arcad/edge v0.0.0-20230322170544-cf8a3f8ac077 h1:vsYcNHZevZrs0VeOTasvJoqvPynb8OvH+MMpIUvNT6Q=
|
||||||
forge.cadoles.com/arcad/edge v0.0.0-20230322170544-cf8a3f8ac077/go.mod h1:ONd6vyQ0IM0vHi1i+bmZBRc1Fd0BoXMuDdY/+0sZefw=
|
forge.cadoles.com/arcad/edge v0.0.0-20230322170544-cf8a3f8ac077/go.mod h1:ONd6vyQ0IM0vHi1i+bmZBRc1Fd0BoXMuDdY/+0sZefw=
|
||||||
|
forge.cadoles.com/arcad/edge v0.0.0-20230328081549-e09de0b0a4f4 h1:ZBBOOKqCEt6F9/Ikkwc2xwYDr7JpLybvxtoRJwXt7Gw=
|
||||||
|
forge.cadoles.com/arcad/edge v0.0.0-20230328081549-e09de0b0a4f4/go.mod h1:ONd6vyQ0IM0vHi1i+bmZBRc1Fd0BoXMuDdY/+0sZefw=
|
||||||
|
forge.cadoles.com/arcad/edge v0.0.0-20230328183829-d8ce2901d2ab h1:xOtzLAYOUcKd/VBx/PzL2riC0zNuQ/cxxf5r3AmEvJE=
|
||||||
|
forge.cadoles.com/arcad/edge v0.0.0-20230328183829-d8ce2901d2ab/go.mod h1:ONd6vyQ0IM0vHi1i+bmZBRc1Fd0BoXMuDdY/+0sZefw=
|
||||||
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
|
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/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=
|
github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
|
||||||
|
@ -84,6 +88,12 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
|
||||||
github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
|
github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
|
||||||
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
|
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
|
||||||
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
|
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
|
||||||
|
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||||
|
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||||
|
github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
|
||||||
|
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||||
|
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
|
||||||
|
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
|
||||||
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||||
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
|
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
|
||||||
|
@ -761,6 +771,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
|
||||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
|
||||||
|
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
|
@ -771,6 +783,7 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
|
||||||
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
|
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ=
|
github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ=
|
||||||
|
@ -974,6 +987,8 @@ github.com/miekg/dns v1.1.51/go.mod h1:2Z9d3CP1LQWihRZUf29mQ19yDThaI4DAYzte2CaQW
|
||||||
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=
|
||||||
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
|
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
|
||||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||||
|
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||||
|
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||||
|
@ -987,6 +1002,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
|
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
||||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||||
github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
|
github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
|
||||||
|
@ -1180,6 +1197,7 @@ github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||||
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
|
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||||
|
@ -1204,6 +1222,8 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd
|
||||||
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
|
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
|
||||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||||
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||||
|
@ -1379,6 +1399,7 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/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-20210921155107-089bfa567519/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.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
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=
|
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
|
|
@ -0,0 +1,190 @@
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec"
|
||||||
|
appSpec "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec"
|
||||||
|
"forge.cadoles.com/Cadoles/emissary/internal/jwk"
|
||||||
|
"forge.cadoles.com/arcad/edge/pkg/app"
|
||||||
|
"forge.cadoles.com/arcad/edge/pkg/bus"
|
||||||
|
"forge.cadoles.com/arcad/edge/pkg/bus/memory"
|
||||||
|
edgeHTTP "forge.cadoles.com/arcad/edge/pkg/http"
|
||||||
|
"forge.cadoles.com/arcad/edge/pkg/module"
|
||||||
|
appModule "forge.cadoles.com/arcad/edge/pkg/module/app"
|
||||||
|
"forge.cadoles.com/arcad/edge/pkg/module/auth"
|
||||||
|
"forge.cadoles.com/arcad/edge/pkg/module/blob"
|
||||||
|
"forge.cadoles.com/arcad/edge/pkg/module/cast"
|
||||||
|
"forge.cadoles.com/arcad/edge/pkg/module/net"
|
||||||
|
"forge.cadoles.com/arcad/edge/pkg/storage/sqlite"
|
||||||
|
"github.com/Masterminds/sprig/v3"
|
||||||
|
"github.com/dop251/goja"
|
||||||
|
"github.com/lestrrat-go/jwx/v2/jwa"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Controller) getHandlerOptions(ctx context.Context, appKey string, specs *spec.Spec) ([]edgeHTTP.HandlerOptionFunc, error) {
|
||||||
|
dataDir, err := c.ensureAppDataDir(ctx, appKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not retrieve app data dir")
|
||||||
|
}
|
||||||
|
|
||||||
|
dbFile := filepath.Join(dataDir, appKey+".sqlite")
|
||||||
|
db, err := sqlite.Open(dbFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "could not open database file '%s'", dbFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
keySet, err := getAuthKeySet(specs.Config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not retrieve auth key set")
|
||||||
|
}
|
||||||
|
|
||||||
|
bundles := make([]string, 0, len(specs.Apps))
|
||||||
|
for appKey, app := range specs.Apps {
|
||||||
|
path := c.getAppBundlePath(appKey, app.Format)
|
||||||
|
bundles = append(bundles, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
getAppURL := createGetAppURL(specs)
|
||||||
|
|
||||||
|
bus := memory.NewBus()
|
||||||
|
modules := getAppModules(bus, db, specs, keySet, getAppURL, bundles)
|
||||||
|
|
||||||
|
options := []edgeHTTP.HandlerOptionFunc{
|
||||||
|
edgeHTTP.WithBus(bus),
|
||||||
|
edgeHTTP.WithServerModules(modules...),
|
||||||
|
}
|
||||||
|
|
||||||
|
return options, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAuthKeySet(config *spec.Config) (jwk.Set, error) {
|
||||||
|
keySet := jwk.NewSet()
|
||||||
|
if config == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
auth := config.Auth
|
||||||
|
|
||||||
|
if auth == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case auth.Local != nil:
|
||||||
|
var (
|
||||||
|
key jwk.Key
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
switch typedKey := auth.Local.Key.(type) {
|
||||||
|
case string:
|
||||||
|
key, err = jwk.FromRaw([]byte(typedKey))
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not parse local auth key")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := key.Set(jwk.AlgorithmKey, jwa.HS256); err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, errors.Errorf("unexpected key type '%T'", auth.Local.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := keySet.AddKey(key); err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return keySet, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createGetAppURL(specs *spec.Spec) GetURLFunc {
|
||||||
|
var (
|
||||||
|
compileOnce sync.Once
|
||||||
|
urlTemplate *template.Template
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
return func(ctx context.Context, manifest *app.Manifest) (string, error) {
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var appURLTemplate string
|
||||||
|
|
||||||
|
if specs.Config == nil || specs.Config.AppURLTemplate == "" {
|
||||||
|
appURLTemplate = `http://{{ last ( splitList "." ( toString .Manifest.ID ) ) }}.local`
|
||||||
|
} else {
|
||||||
|
appURLTemplate = specs.Config.AppURLTemplate
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOnce.Do(func() {
|
||||||
|
urlTemplate, err = template.New("").Funcs(sprig.TxtFuncMap()).Parse(appURLTemplate)
|
||||||
|
})
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
data := struct {
|
||||||
|
Manifest *app.Manifest
|
||||||
|
Specs *spec.Spec
|
||||||
|
}{
|
||||||
|
Manifest: manifest,
|
||||||
|
Specs: specs,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := urlTemplate.Execute(&buf, data); err != nil {
|
||||||
|
return "", errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAppModules(bus bus.Bus, db *sql.DB, spec *appSpec.Spec, keySet jwk.Set, getAppURL GetURLFunc, bundles []string) []app.ServerModuleFactory {
|
||||||
|
ds := sqlite.NewDocumentStoreWithDB(db)
|
||||||
|
bs := sqlite.NewBlobStoreWithDB(db)
|
||||||
|
|
||||||
|
return []app.ServerModuleFactory{
|
||||||
|
module.ContextModuleFactory(),
|
||||||
|
module.ConsoleModuleFactory(),
|
||||||
|
cast.CastModuleFactory(),
|
||||||
|
module.LifecycleModuleFactory(),
|
||||||
|
net.ModuleFactory(bus),
|
||||||
|
module.RPCModuleFactory(bus),
|
||||||
|
module.StoreModuleFactory(ds),
|
||||||
|
blob.ModuleFactory(bus, bs),
|
||||||
|
module.Extends(
|
||||||
|
auth.ModuleFactory(
|
||||||
|
auth.WithJWT(func() (jwk.Set, error) {
|
||||||
|
return keySet, nil
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
func(o *goja.Object) {
|
||||||
|
if err := o.Set("CLAIM_TENANT", "arcad_tenant"); err != nil {
|
||||||
|
panic(errors.New("could not set 'CLAIM_TENANT' property"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := o.Set("CLAIM_ENTRYPOINT", "arcad_entrypoint"); err != nil {
|
||||||
|
panic(errors.New("could not set 'CLAIM_ENTRYPOINT' property"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := o.Set("CLAIM_ROLE", "arcad_role"); err != nil {
|
||||||
|
panic(errors.New("could not set 'CLAIM_ROLE' property"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := o.Set("CLAIM_PREFERRED_USERNAME", "preferred_username"); err != nil {
|
||||||
|
panic(errors.New("could not set 'CLAIM_PREFERRED_USERNAME' property"))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
appModule.ModuleFactory(NewAppRepository(getAppURL, bundles...)),
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"forge.cadoles.com/arcad/edge/pkg/app"
|
||||||
|
"forge.cadoles.com/arcad/edge/pkg/bundle"
|
||||||
|
appModule "forge.cadoles.com/arcad/edge/pkg/module/app"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gitlab.com/wpetit/goweb/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetURLFunc func(context.Context, *app.Manifest) (string, error)
|
||||||
|
|
||||||
|
type AppRepository struct {
|
||||||
|
getURL GetURLFunc
|
||||||
|
bundles []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get implements app.Repository
|
||||||
|
func (r *AppRepository) Get(ctx context.Context, id app.ID) (*app.Manifest, error) {
|
||||||
|
manifest, err := r.findManifest(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return manifest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetURL implements app.Repository
|
||||||
|
func (r *AppRepository) GetURL(ctx context.Context, id app.ID) (string, error) {
|
||||||
|
manifest, err := r.findManifest(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
url, err := r.getURL(ctx, manifest)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return url, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// List implements app.Repository
|
||||||
|
func (r *AppRepository) List(ctx context.Context) ([]*app.Manifest, error) {
|
||||||
|
manifests := make([]*app.Manifest, 0)
|
||||||
|
|
||||||
|
for _, path := range r.bundles {
|
||||||
|
bundleCtx := logger.With(ctx, logger.F("path", path))
|
||||||
|
|
||||||
|
bundle, err := bundle.FromPath(path)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(bundleCtx, "could not load bundle", logger.E(errors.WithStack(err)))
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
manifest, err := app.LoadManifest(bundle)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(bundleCtx, "could not load manifest", logger.E(errors.WithStack(err)))
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
manifests = append(manifests, manifest)
|
||||||
|
}
|
||||||
|
|
||||||
|
return manifests, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *AppRepository) findManifest(ctx context.Context, id app.ID) (*app.Manifest, error) {
|
||||||
|
for _, path := range r.bundles {
|
||||||
|
bundleCtx := logger.With(ctx, logger.F("path", path))
|
||||||
|
|
||||||
|
bundle, err := bundle.FromPath(path)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(bundleCtx, "could not load bundle", logger.E(errors.WithStack(err)))
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
manifest, err := app.LoadManifest(bundle)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(bundleCtx, "could not load manifest", logger.E(errors.WithStack(err)))
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if manifest.ID != id {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return manifest, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.WithStack(appModule.ErrNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAppRepository(getURL GetURLFunc, bundles ...string) *AppRepository {
|
||||||
|
return &AppRepository{getURL, bundles}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ appModule.Repository = &AppRepository{}
|
|
@ -8,9 +8,8 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/agent"
|
"forge.cadoles.com/Cadoles/emissary/internal/agent"
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/spec/app"
|
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec"
|
||||||
"forge.cadoles.com/arcad/edge/pkg/bundle"
|
"forge.cadoles.com/arcad/edge/pkg/bundle"
|
||||||
"forge.cadoles.com/arcad/edge/pkg/storage/sqlite"
|
|
||||||
"github.com/mitchellh/hashstructure/v2"
|
"github.com/mitchellh/hashstructure/v2"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gitlab.com/wpetit/goweb/logger"
|
"gitlab.com/wpetit/goweb/logger"
|
||||||
|
@ -35,9 +34,9 @@ func (c *Controller) Name() string {
|
||||||
|
|
||||||
// Reconcile implements node.Controller.
|
// Reconcile implements node.Controller.
|
||||||
func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error {
|
func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error {
|
||||||
appSpec := app.NewSpec()
|
appSpec := spec.NewSpec()
|
||||||
|
|
||||||
if err := state.GetSpec(app.NameApp, appSpec); err != nil {
|
if err := state.GetSpec(spec.Name, appSpec); err != nil {
|
||||||
if errors.Is(err, agent.ErrSpecNotFound) {
|
if errors.Is(err, agent.ErrSpecNotFound) {
|
||||||
logger.Info(ctx, "could not find app spec")
|
logger.Info(ctx, "could not find app spec")
|
||||||
|
|
||||||
|
@ -56,7 +55,7 @@ func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) stopAllApps(ctx context.Context, spec *app.Spec) {
|
func (c *Controller) stopAllApps(ctx context.Context, spec *spec.Spec) {
|
||||||
if len(c.servers) > 0 {
|
if len(c.servers) > 0 {
|
||||||
logger.Info(ctx, "stopping all apps")
|
logger.Info(ctx, "stopping all apps")
|
||||||
}
|
}
|
||||||
|
@ -76,122 +75,121 @@ func (c *Controller) stopAllApps(ctx context.Context, spec *app.Spec) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) updateApps(ctx context.Context, spec *app.Spec) {
|
func (c *Controller) updateApps(ctx context.Context, specs *spec.Spec) {
|
||||||
// Stop and remove obsolete apps
|
// Stop and remove obsolete apps
|
||||||
for appID, entry := range c.servers {
|
for appKey, server := range c.servers {
|
||||||
if _, exists := spec.Apps[appID]; exists {
|
if _, exists := specs.Apps[appKey]; exists {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info(ctx, "stopping app", logger.F("appID", appID))
|
logger.Info(ctx, "stopping app", logger.F("appKey", appKey))
|
||||||
|
|
||||||
if err := entry.Server.Stop(); err != nil {
|
if err := server.Server.Stop(); err != nil {
|
||||||
logger.Error(
|
logger.Error(
|
||||||
ctx, "error while stopping app",
|
ctx, "error while stopping app",
|
||||||
logger.F("gatewayID", appID),
|
logger.F("appKey", appKey),
|
||||||
logger.E(errors.WithStack(err)),
|
logger.E(errors.WithStack(err)),
|
||||||
)
|
)
|
||||||
|
|
||||||
delete(c.servers, appID)
|
delete(c.servers, appKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// (Re)start apps
|
// (Re)start apps
|
||||||
for appID, appSpec := range spec.Apps {
|
for appKey := range specs.Apps {
|
||||||
appCtx := logger.With(ctx, logger.F("appID", appID))
|
appCtx := logger.With(ctx, logger.F("appKey", appKey))
|
||||||
|
|
||||||
if err := c.updateApp(ctx, appID, appSpec, spec.Auth); err != nil {
|
if err := c.updateApp(ctx, specs, appKey); err != nil {
|
||||||
logger.Error(appCtx, "could not update app", logger.E(errors.WithStack(err)))
|
logger.Error(appCtx, "could not update app", logger.E(errors.WithStack(err)))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) updateApp(ctx context.Context, appID string, appSpec app.AppEntry, auth *app.Auth) (err error) {
|
func (c *Controller) updateApp(ctx context.Context, specs *spec.Spec, appKey string) (err error) {
|
||||||
newAppSpecHash, err := hashstructure.Hash(appSpec, hashstructure.FormatV2, nil)
|
appEntry := specs.Apps[appKey]
|
||||||
|
|
||||||
|
newAppSpecHash, err := hashstructure.Hash(appEntry, hashstructure.FormatV2, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bundle, sha256sum, err := c.ensureAppBundle(ctx, appID, appSpec)
|
bundle, sha256sum, err := c.ensureAppBundle(ctx, appKey, appEntry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "could not download app bundle")
|
return errors.Wrap(err, "could not download app bundle")
|
||||||
}
|
}
|
||||||
|
|
||||||
dataDir, err := c.ensureAppDataDir(ctx, appID)
|
server, exists := c.servers[appKey]
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "could not retrieve app data dir")
|
|
||||||
}
|
|
||||||
|
|
||||||
var entry *serverEntry
|
|
||||||
|
|
||||||
entry, exists := c.servers[appID]
|
|
||||||
if !exists {
|
if !exists {
|
||||||
logger.Info(ctx, "app currently not running")
|
logger.Info(ctx, "app currently not running")
|
||||||
} else if sha256sum != appSpec.SHA256Sum {
|
} else if sha256sum != appEntry.SHA256Sum {
|
||||||
logger.Info(
|
logger.Info(
|
||||||
ctx, "bundle hash mismatch, stopping app",
|
ctx, "bundle hash mismatch, stopping app",
|
||||||
logger.F("currentHash", sha256sum),
|
logger.F("currentHash", sha256sum),
|
||||||
logger.F("specHash", appSpec.SHA256Sum),
|
logger.F("specHash", appEntry.SHA256Sum),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := entry.Server.Stop(); err != nil {
|
if err := server.Server.Stop(); err != nil {
|
||||||
return errors.Wrap(err, "could not stop app")
|
return errors.Wrap(err, "could not stop app")
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = nil
|
server = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if entry == nil {
|
if server == nil {
|
||||||
dbFile := filepath.Join(dataDir, appID+".sqlite")
|
options, err := c.getHandlerOptions(ctx, appKey, specs)
|
||||||
db, err := sqlite.Open(dbFile)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "could not opend database file '%s'", dbFile)
|
return errors.Wrap(err, "could not create handler options")
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = &serverEntry{
|
var auth *spec.Auth
|
||||||
Server: NewServer(bundle, db, auth),
|
if specs.Config != nil {
|
||||||
|
auth = specs.Config.Auth
|
||||||
|
}
|
||||||
|
|
||||||
|
server = &serverEntry{
|
||||||
|
Server: NewServer(bundle, auth, options...),
|
||||||
SpecHash: 0,
|
SpecHash: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
c.servers[appID] = entry
|
c.servers[appKey] = server
|
||||||
}
|
}
|
||||||
|
|
||||||
specChanged := newAppSpecHash != entry.SpecHash
|
specChanged := newAppSpecHash != server.SpecHash
|
||||||
|
|
||||||
if entry.Server.Running() && !specChanged {
|
if server.Server.Running() && !specChanged {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if specChanged && entry.SpecHash != 0 {
|
if specChanged && server.SpecHash != 0 {
|
||||||
logger.Info(
|
logger.Info(
|
||||||
ctx, "restarting app",
|
ctx, "restarting app",
|
||||||
logger.F("address", appSpec.Address),
|
logger.F("address", appEntry.Address),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
logger.Info(
|
logger.Info(
|
||||||
ctx, "starting app",
|
ctx, "starting app",
|
||||||
logger.F("address", appSpec.Address),
|
logger.F("address", appEntry.Address),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := entry.Server.Start(ctx, appSpec.Address); err != nil {
|
if err := server.Server.Start(ctx, appEntry.Address); err != nil {
|
||||||
delete(c.servers, appID)
|
delete(c.servers, appKey)
|
||||||
|
|
||||||
return errors.Wrap(err, "could not start app")
|
return errors.Wrap(err, "could not start app")
|
||||||
}
|
}
|
||||||
|
|
||||||
entry.SpecHash = newAppSpecHash
|
server.SpecHash = newAppSpecHash
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) ensureAppBundle(ctx context.Context, appID string, spec app.AppEntry) (bundle.Bundle, string, error) {
|
func (c *Controller) ensureAppBundle(ctx context.Context, appID string, spec spec.AppEntry) (bundle.Bundle, string, error) {
|
||||||
if err := os.MkdirAll(c.downloadDir, os.ModePerm); err != nil {
|
if err := os.MkdirAll(c.downloadDir, os.ModePerm); err != nil {
|
||||||
return nil, "", errors.WithStack(err)
|
return nil, "", errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bundlePath := filepath.Join(c.downloadDir, appID+"."+spec.Format)
|
bundlePath := c.getAppBundlePath(appID, spec.Format)
|
||||||
|
|
||||||
_, err := os.Stat(bundlePath)
|
_, err := os.Stat(bundlePath)
|
||||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||||
|
@ -285,6 +283,10 @@ func (c *Controller) ensureAppDataDir(ctx context.Context, appID string) (string
|
||||||
return dataDir, nil
|
return dataDir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Controller) getAppBundlePath(appKey string, format string) string {
|
||||||
|
return filepath.Join(c.downloadDir, appKey+"."+format)
|
||||||
|
}
|
||||||
|
|
||||||
func NewController(funcs ...OptionFunc) *Controller {
|
func NewController(funcs ...OptionFunc) *Controller {
|
||||||
opts := defaultOptions()
|
opts := defaultOptions()
|
||||||
for _, fn := range funcs {
|
for _, fn := range funcs {
|
||||||
|
|
|
@ -2,26 +2,17 @@ package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
appSpec "forge.cadoles.com/Cadoles/emissary/internal/spec/app"
|
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec"
|
||||||
"forge.cadoles.com/arcad/edge/pkg/app"
|
appSpec "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec"
|
||||||
"forge.cadoles.com/arcad/edge/pkg/bus"
|
|
||||||
"forge.cadoles.com/arcad/edge/pkg/bus/memory"
|
|
||||||
edgeHTTP "forge.cadoles.com/arcad/edge/pkg/http"
|
edgeHTTP "forge.cadoles.com/arcad/edge/pkg/http"
|
||||||
"forge.cadoles.com/arcad/edge/pkg/module"
|
|
||||||
"forge.cadoles.com/arcad/edge/pkg/module/auth"
|
|
||||||
authHTTP "forge.cadoles.com/arcad/edge/pkg/module/auth/http"
|
authHTTP "forge.cadoles.com/arcad/edge/pkg/module/auth/http"
|
||||||
"forge.cadoles.com/arcad/edge/pkg/module/cast"
|
|
||||||
"forge.cadoles.com/arcad/edge/pkg/module/net"
|
|
||||||
"forge.cadoles.com/arcad/edge/pkg/storage"
|
|
||||||
"forge.cadoles.com/arcad/edge/pkg/storage/sqlite"
|
|
||||||
"gitlab.com/wpetit/goweb/logger"
|
"gitlab.com/wpetit/goweb/logger"
|
||||||
|
|
||||||
"forge.cadoles.com/arcad/edge/pkg/bundle"
|
"forge.cadoles.com/arcad/edge/pkg/bundle"
|
||||||
"github.com/dop251/goja"
|
|
||||||
"github.com/go-chi/chi/middleware"
|
"github.com/go-chi/chi/middleware"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/lestrrat-go/jwx/v2/jwa"
|
"github.com/lestrrat-go/jwx/v2/jwa"
|
||||||
|
@ -31,13 +22,14 @@ import (
|
||||||
_ "forge.cadoles.com/Cadoles/emissary/internal/imports/passwd"
|
_ "forge.cadoles.com/Cadoles/emissary/internal/imports/passwd"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const defaultCookieDuration time.Duration = 24 * time.Hour
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
bundle bundle.Bundle
|
bundle bundle.Bundle
|
||||||
db *sql.DB
|
handlerOptions []edgeHTTP.HandlerOptionFunc
|
||||||
server *http.Server
|
server *http.Server
|
||||||
serverMutex sync.RWMutex
|
serverMutex sync.RWMutex
|
||||||
auth *appSpec.Auth
|
auth *appSpec.Auth
|
||||||
keySet jwk.Set
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Start(ctx context.Context, addr string) (err error) {
|
func (s *Server) Start(ctx context.Context, addr string) (err error) {
|
||||||
|
@ -51,47 +43,13 @@ func (s *Server) Start(ctx context.Context, addr string) (err error) {
|
||||||
|
|
||||||
router.Use(middleware.Logger)
|
router.Use(middleware.Logger)
|
||||||
|
|
||||||
bus := memory.NewBus()
|
handler := edgeHTTP.NewHandler(s.handlerOptions...)
|
||||||
ds := sqlite.NewDocumentStoreWithDB(s.db)
|
|
||||||
bs := sqlite.NewBlobStoreWithDB(s.db)
|
|
||||||
|
|
||||||
handler := edgeHTTP.NewHandler(
|
|
||||||
edgeHTTP.WithBus(bus),
|
|
||||||
edgeHTTP.WithServerModules(s.getAppModules(bus, ds, bs)...),
|
|
||||||
)
|
|
||||||
if err := handler.Load(s.bundle); err != nil {
|
if err := handler.Load(s.bundle); err != nil {
|
||||||
return errors.Wrap(err, "could not load app bundle")
|
return errors.Wrap(err, "could not load app bundle")
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.auth != nil {
|
if err := s.configureAuth(router, s.auth); err != nil {
|
||||||
if s.auth.Local != nil {
|
return errors.WithStack(err)
|
||||||
var rawKey any = s.auth.Local.Key
|
|
||||||
if strKey, ok := rawKey.(string); ok {
|
|
||||||
rawKey = []byte(strKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
key, err := jwk.FromRaw(rawKey)
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := key.Set(jwk.AlgorithmKey, jwa.HS256); err != nil {
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
keySet := jwk.NewSet()
|
|
||||||
if err := keySet.AddKey(key); err != nil {
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.keySet = keySet
|
|
||||||
|
|
||||||
router.Handle("/auth/*", authHTTP.NewLocalHandler(
|
|
||||||
jwa.HS256, key,
|
|
||||||
authHTTP.WithRoutePrefix("/auth"),
|
|
||||||
authHTTP.WithAccounts(s.auth.Local.Accounts...),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
router.Handle("/*", handler)
|
router.Handle("/*", handler)
|
||||||
|
@ -157,49 +115,46 @@ func (s *Server) Stop() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getAppModules(bus bus.Bus, ds storage.DocumentStore, bs storage.BlobStore) []app.ServerModuleFactory {
|
func (s *Server) configureAuth(router chi.Router, auth *spec.Auth) error {
|
||||||
return []app.ServerModuleFactory{
|
if auth == nil {
|
||||||
module.ContextModuleFactory(),
|
return nil
|
||||||
module.ConsoleModuleFactory(),
|
|
||||||
cast.CastModuleFactory(),
|
|
||||||
module.LifecycleModuleFactory(),
|
|
||||||
net.ModuleFactory(bus),
|
|
||||||
module.RPCModuleFactory(bus),
|
|
||||||
module.StoreModuleFactory(ds),
|
|
||||||
module.BlobModuleFactory(bus, bs),
|
|
||||||
module.Extends(
|
|
||||||
auth.ModuleFactory(
|
|
||||||
auth.WithJWT(s.getJWTKeySet),
|
|
||||||
),
|
|
||||||
func(o *goja.Object) {
|
|
||||||
if err := o.Set("CLAIM_TENANT", "arcad_tenant"); err != nil {
|
|
||||||
panic(errors.New("could not set 'CLAIM_TENANT' property"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := o.Set("CLAIM_ENTRYPOINT", "arcad_entrypoint"); err != nil {
|
|
||||||
panic(errors.New("could not set 'CLAIM_ENTRYPOINT' property"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := o.Set("CLAIM_ROLE", "arcad_role"); err != nil {
|
|
||||||
panic(errors.New("could not set 'CLAIM_ROLE' property"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := o.Set("CLAIM_PREFERRED_USERNAME", "preferred_username"); err != nil {
|
|
||||||
panic(errors.New("could not set 'CLAIM_PREFERRED_USERNAME' property"))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case auth.Local != nil:
|
||||||
|
var rawKey any = s.auth.Local.Key
|
||||||
|
if strKey, ok := rawKey.(string); ok {
|
||||||
|
rawKey = []byte(strKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := jwk.FromRaw(rawKey)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cookieDuration := defaultCookieDuration
|
||||||
|
if s.auth.Local.CookieDuration != "" {
|
||||||
|
cookieDuration, err = time.ParseDuration(s.auth.Local.CookieDuration)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
router.Handle("/auth/*", authHTTP.NewLocalHandler(
|
||||||
|
jwa.HS256, key,
|
||||||
|
authHTTP.WithRoutePrefix("/auth"),
|
||||||
|
authHTTP.WithAccounts(s.auth.Local.Accounts...),
|
||||||
|
authHTTP.WithCookieOptions(s.auth.Local.CookieDomain, cookieDuration),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getJWTKeySet() (jwk.Set, error) {
|
func NewServer(bundle bundle.Bundle, auth *appSpec.Auth, handlerOptions ...edgeHTTP.HandlerOptionFunc) *Server {
|
||||||
return s.keySet, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewServer(bundle bundle.Bundle, db *sql.DB, auth *appSpec.Auth) *Server {
|
|
||||||
return &Server{
|
return &Server{
|
||||||
bundle: bundle,
|
bundle: bundle,
|
||||||
db: db,
|
auth: auth,
|
||||||
auth: auth,
|
handlerOptions: handlerOptions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package app
|
package spec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
@ -11,7 +11,7 @@ import (
|
||||||
var schema []byte
|
var schema []byte
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
if err := spec.Register(NameApp, schema); err != nil {
|
if err := spec.Register(Name, schema); err != nil {
|
||||||
panic(errors.WithStack(err))
|
panic(errors.WithStack(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -71,6 +71,12 @@
|
||||||
"algo"
|
"algo"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"cookieDomain": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"cookieDuration": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
@ -78,6 +84,11 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"appUrlTemplate": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
|
@ -1,16 +1,16 @@
|
||||||
package app
|
package spec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
||||||
edgeAuth "forge.cadoles.com/arcad/edge/pkg/module/auth/http"
|
edgeAuth "forge.cadoles.com/arcad/edge/pkg/module/auth/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
const NameApp spec.Name = "app.emissary.cadoles.com"
|
const Name spec.Name = "app.emissary.cadoles.com"
|
||||||
|
|
||||||
type Spec struct {
|
type Spec struct {
|
||||||
Revision int `json:"revision"`
|
Revision int `json:"revision"`
|
||||||
Apps map[string]AppEntry `json:"apps"`
|
Apps map[string]AppEntry `json:"apps"`
|
||||||
Auth *Auth `json:"auth"`
|
Config *Config `json:"config"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppEntry struct {
|
type AppEntry struct {
|
||||||
|
@ -25,12 +25,19 @@ type Auth struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type LocalAuth struct {
|
type LocalAuth struct {
|
||||||
Key any `json:"key"`
|
Key any `json:"key"`
|
||||||
Accounts []edgeAuth.LocalAccount `json:"accounts"`
|
Accounts []edgeAuth.LocalAccount `json:"accounts"`
|
||||||
|
CookieDomain string `json:"cookieDomain"`
|
||||||
|
CookieDuration string `json:"cookieDuration"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Auth *Auth `json:"auth"`
|
||||||
|
AppURLTemplate string `json:"appUrlTemplate"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Spec) SpecName() spec.Name {
|
func (s *Spec) SpecName() spec.Name {
|
||||||
return NameApp
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Spec) SpecRevision() int {
|
func (s *Spec) SpecRevision() int {
|
||||||
|
@ -39,8 +46,8 @@ func (s *Spec) SpecRevision() int {
|
||||||
|
|
||||||
func (s *Spec) SpecData() map[string]any {
|
func (s *Spec) SpecData() map[string]any {
|
||||||
return map[string]any{
|
return map[string]any{
|
||||||
"apps": s.Apps,
|
"apps": s.Apps,
|
||||||
"auth": s.Auth,
|
"config": s.Config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package app
|
package spec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -28,7 +28,7 @@ func TestValidator(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
validator := spec.NewValidator()
|
validator := spec.NewValidator()
|
||||||
if err := validator.Register(NameApp, schema); err != nil {
|
if err := validator.Register(Name, schema); err != nil {
|
||||||
t.Fatalf("+%v", errors.WithStack(err))
|
t.Fatalf("+%v", errors.WithStack(err))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package spec
|
package spec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
_ "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/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/app"
|
|
||||||
_ "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"
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,6 +23,13 @@ type (
|
||||||
ParseOption = jwk.ParseOption
|
ParseOption = jwk.ParseOption
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
FromRaw = jwk.FromRaw
|
||||||
|
NewSet = jwk.NewSet
|
||||||
|
)
|
||||||
|
|
||||||
|
const AlgorithmKey = jwk.AlgorithmKey
|
||||||
|
|
||||||
func Parse(src []byte, options ...jwk.ParseOption) (Set, error) {
|
func Parse(src []byte, options ...jwk.ParseOption) (Set, error) {
|
||||||
return jwk.Parse(src, options...)
|
return jwk.Parse(src, options...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ package proxy
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"forge.cadoles.com/arcad/edge/pkg/proxy/wildcard"
|
"forge.cadoles.com/Cadoles/emissary/internal/proxy/wildcard"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FilterHosts(allowedHostPatterns ...string) Middleware {
|
func FilterHosts(allowedHostPatterns ...string) Middleware {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"forge.cadoles.com/arcad/edge/pkg/proxy/wildcard"
|
"forge.cadoles.com/Cadoles/emissary/internal/proxy/wildcard"
|
||||||
"gitlab.com/wpetit/goweb/logger"
|
"gitlab.com/wpetit/goweb/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ func RewriteHosts(mappings map[string]*url.URL) Middleware {
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Strings(patterns)
|
sort.Strings(patterns)
|
||||||
|
reverse(patterns)
|
||||||
|
|
||||||
return func(h http.Handler) http.Handler {
|
return func(h http.Handler) http.Handler {
|
||||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"apps": {
|
|
||||||
"edge.sdk.client.test": {
|
|
||||||
"url": "http://localhost:3001/edge.sdk.client.test_0.0.0.zip",
|
|
||||||
"sha256sum": "58019192dacdae17755707719707db007e26dac856102280583fbd18427dd352",
|
|
||||||
"format": "zip",
|
|
||||||
"address": "127.0.0.1:8081"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
@baseUrl = http://localhost:3000
|
|
||||||
|
|
||||||
### Get agents
|
|
||||||
|
|
||||||
# @name getAgents
|
|
||||||
GET {{ baseUrl }}/api/v1/agents
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
@agentId = {{ getAgents.response.body.Data.Agents.0.ID }}
|
|
||||||
|
|
||||||
### Update an agent (accept it)
|
|
||||||
|
|
||||||
PUT {{ baseUrl }}/api/v1/agents/{{ agentId }}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"Status": 1
|
|
||||||
}
|
|
||||||
|
|
||||||
### Get an agent
|
|
||||||
|
|
||||||
GET {{ baseUrl }}/api/v1/agents/{{ agentId }}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
### Get an agent specs
|
|
||||||
|
|
||||||
# @name getSpecs
|
|
||||||
GET {{ baseUrl }}/api/v1/agents/{{ agentId }}/specs
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
@specName = {{ getSpecs.response.body.Data.Specs.0.Name }}
|
|
||||||
|
|
||||||
### Update an agent specs
|
|
||||||
|
|
||||||
POST {{ baseUrl }}/api/v1/agents/{{ agentId }}/specs
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"Name": "gateway.emissary.cadoles.com",
|
|
||||||
"Revision": 2,
|
|
||||||
"Data": {
|
|
||||||
"gateways": {
|
|
||||||
"cadoles.com":{
|
|
||||||
"address":":3003",
|
|
||||||
"target":"https://www.cadoles.com"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
### Delete an agent spec
|
|
||||||
|
|
||||||
DELETE {{ baseUrl }}/api/v1/agents/{{ agentId }}/specs
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"Name": "gateway.emissary.cadoles.com"
|
|
||||||
}
|
|
||||||
|
|
||||||
### Update UCI spec with uhttpd config
|
|
||||||
|
|
||||||
POST {{ baseUrl }}/api/v1/agents/2/specs
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
< ./uci-spec.payload.json
|
|
|
@ -1,163 +0,0 @@
|
||||||
{
|
|
||||||
"Name": "uci.emissary.cadoles.com",
|
|
||||||
"Revision": 6,
|
|
||||||
"Data": {
|
|
||||||
"config": {
|
|
||||||
"packages": [
|
|
||||||
{
|
|
||||||
"name": "uhttpd",
|
|
||||||
"configs": [
|
|
||||||
{
|
|
||||||
"name": "uhttpd",
|
|
||||||
"section": "main",
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"type": "list",
|
|
||||||
"name": "listen_http",
|
|
||||||
"value": "0.0.0.0:8080"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "list",
|
|
||||||
"name": "listen_http",
|
|
||||||
"value": "[::]:8080"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "list",
|
|
||||||
"name": "listen_https",
|
|
||||||
"value": "0.0.0.0:8443"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "list",
|
|
||||||
"name": "listen_https",
|
|
||||||
"value": "[::]:8443"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "redirect_https",
|
|
||||||
"value": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "home",
|
|
||||||
"value": "/www"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "rfc1918_filter",
|
|
||||||
"value": "1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "max_requests",
|
|
||||||
"value": "3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "max_connections",
|
|
||||||
"value": "100"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "cert",
|
|
||||||
"value": "/etc/uhttpd.crt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "key",
|
|
||||||
"value": "/etc/uhttpd.key"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "cgi_prefix",
|
|
||||||
"value": "/cgi-bin"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "list",
|
|
||||||
"name": "lua_prefix",
|
|
||||||
"value": "/cgi-bin/luci=/usr/lib/lua/luci/sgi/uhttpd.lua"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "script_timeout",
|
|
||||||
"value": "60"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "network_timeout",
|
|
||||||
"value": "30"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "http_keepalive",
|
|
||||||
"value": "20"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "tcp_keepalive",
|
|
||||||
"value": "1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "ubus_prefix",
|
|
||||||
"value": "/ubus"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "cert",
|
|
||||||
"section": "defaults",
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "days",
|
|
||||||
"value": "730"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "key_type",
|
|
||||||
"value": "ec"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "bits",
|
|
||||||
"value": "2048"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "ec_curve",
|
|
||||||
"value": "P-256"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "country",
|
|
||||||
"value": "ZZ"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "state",
|
|
||||||
"value": "Somewhere"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "location",
|
|
||||||
"value": "Unknown"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "option",
|
|
||||||
"name": "commonname",
|
|
||||||
"value": "OpenWrt"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"postImportCommands": [
|
|
||||||
{
|
|
||||||
"command": "reload_config",
|
|
||||||
"args": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
{
|
||||||
|
"apps": {
|
||||||
|
"portal": {
|
||||||
|
"url": "https://emissary.cadol.es/files/apps/arcad.portal_v2023.3.28-3feda80.zip",
|
||||||
|
"sha256sum": "921402c44a5fa554d5b630d1284957b05416aa6872b402314cf52e964e06fac5",
|
||||||
|
"address": "127.0.0.1:8082",
|
||||||
|
"format": "zip"
|
||||||
|
},
|
||||||
|
"hextris": {
|
||||||
|
"url": "https://emissary.cadol.es/files/apps/app.arcad.edge.hextris_v2023.3.22-33ece28.zip",
|
||||||
|
"sha256sum": "5f9f3c8d6f22796beb051d747d7ff12efa17af9d1552c0ab08baef13703a2aba",
|
||||||
|
"address": "127.0.0.1:8083",
|
||||||
|
"format": "zip"
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"url": "https://emissary.cadol.es/files/apps/edge.sdk.client.test_v2023.3.24-ed535b6.zip",
|
||||||
|
"sha256sum": "e97b7b79159bb5d6a13b05644c091272b02a1a3cbb1b613dd5eda37e1eb84623",
|
||||||
|
"address": "127.0.0.1:8084",
|
||||||
|
"format": "zip"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"appUrlTemplate": "http://{{ last ( splitList \".\" ( toString .Manifest.ID ) ) }}.arcad.local:8080",
|
||||||
|
"auth": {
|
||||||
|
"local": {
|
||||||
|
"key": "absolutlynotsecret",
|
||||||
|
"cookieDomain": ".arcad.local",
|
||||||
|
"cookieDuration": "1h",
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"username": "admin",
|
||||||
|
"algo": "plain",
|
||||||
|
"password": "admin",
|
||||||
|
"claims": {
|
||||||
|
"arcad_role": "admin",
|
||||||
|
"arcad_tenant": "x86",
|
||||||
|
"preferred_username": "Admin",
|
||||||
|
"sub": "admin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"proxies": {
|
||||||
|
"main": {
|
||||||
|
"address": ":8080",
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"hostPattern": "portal.arcad.local:*",
|
||||||
|
"target": "http://localhost:8082"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hostPattern": "hextris.arcad.local:*",
|
||||||
|
"target": "http://localhost:8083"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hostPattern": "test.arcad.local:*",
|
||||||
|
"target": "http://localhost:8084"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hostPattern": "*",
|
||||||
|
"target": "http://localhost:8082"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue