feat(controller,app): add edge apps controller
This commit is contained in:
17
internal/spec/app/init.go
Normal file
17
internal/spec/app/init.go
Normal file
@ -0,0 +1,17 @@
|
||||
package app
|
||||
|
||||
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(NameApp, schema); err != nil {
|
||||
panic(errors.WithStack(err))
|
||||
}
|
||||
}
|
36
internal/spec/app/schema.json
Normal file
36
internal/spec/app/schema.json
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://app.emissary.cadoles.com/spec.json",
|
||||
"title": "AppSpec",
|
||||
"description": "Emissary 'App' specification",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"apps": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
".*": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"sha256sum": {
|
||||
"type": "string"
|
||||
},
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"format": {
|
||||
"type": "string",
|
||||
"enum": ["zip", "tar.gz"]
|
||||
}
|
||||
},
|
||||
"required": ["url", "sha256sum", "address", "format"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["apps"],
|
||||
"additionalProperties": false
|
||||
}
|
39
internal/spec/app/spec.go
Normal file
39
internal/spec/app/spec.go
Normal file
@ -0,0 +1,39 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
||||
)
|
||||
|
||||
const NameApp spec.Name = "app.emissary.cadoles.com"
|
||||
|
||||
type Spec struct {
|
||||
Revision int `json:"revisions"`
|
||||
Apps map[string]AppEntry
|
||||
}
|
||||
|
||||
type AppEntry struct {
|
||||
URL string `json:"url"`
|
||||
SHA256Sum string `json:"sha256sum"`
|
||||
Address string `json:"address"`
|
||||
Format string `json:"format"`
|
||||
}
|
||||
|
||||
func (s *Spec) SpecName() spec.Name {
|
||||
return NameApp
|
||||
}
|
||||
|
||||
func (s *Spec) SpecRevision() int {
|
||||
return s.Revision
|
||||
}
|
||||
|
||||
func (s *Spec) SpecData() map[string]any {
|
||||
return map[string]any{
|
||||
"apps": s.Apps,
|
||||
}
|
||||
}
|
||||
|
||||
func NewSpec() *Spec {
|
||||
return &Spec{}
|
||||
}
|
||||
|
||||
var _ spec.Spec = &Spec{}
|
7
internal/spec/app/testdata/spec-ok.json
vendored
Normal file
7
internal/spec/app/testdata/spec-ok.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "app.emissary.cadoles.com",
|
||||
"data": {
|
||||
"apps": {}
|
||||
},
|
||||
"revision": 0
|
||||
}
|
65
internal/spec/app/validator_test.go
Normal file
65
internal/spec/app/validator_test.go
Normal file
@ -0,0 +1,65 @@
|
||||
package app
|
||||
|
||||
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(NameApp, 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)
|
||||
}
|
||||
}
|
@ -24,10 +24,10 @@ func (s *Spec) SpecRevision() int {
|
||||
return s.Revision
|
||||
}
|
||||
|
||||
func (s *Spec) SpecData() any {
|
||||
return struct {
|
||||
Gateways map[ID]GatewayEntry
|
||||
}{Gateways: s.Gateways}
|
||||
func (s *Spec) SpecData() map[string]any {
|
||||
return map[string]any{
|
||||
"gateways": s.Gateways,
|
||||
}
|
||||
}
|
||||
|
||||
func NewSpec() *Spec {
|
||||
@ -35,3 +35,5 @@ func NewSpec() *Spec {
|
||||
Gateways: make(map[ID]GatewayEntry),
|
||||
}
|
||||
}
|
||||
|
||||
var _ spec.Spec = &Spec{}
|
||||
|
@ -1,17 +1,15 @@
|
||||
package spec
|
||||
|
||||
import "forge.cadoles.com/Cadoles/emissary/internal/agent/metadata"
|
||||
|
||||
type Spec interface {
|
||||
SpecName() Name
|
||||
SpecRevision() int
|
||||
SpecData() metadata.Metadata
|
||||
SpecData() map[string]any
|
||||
}
|
||||
|
||||
type RawSpec struct {
|
||||
Name Name `json:"name"`
|
||||
Revision int `json:"revision"`
|
||||
Data metadata.Metadata `json:"data"`
|
||||
Name Name `json:"name"`
|
||||
Revision int `json:"revision"`
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
func (s *RawSpec) SpecName() Name {
|
||||
@ -22,6 +20,8 @@ func (s *RawSpec) SpecRevision() int {
|
||||
return s.Revision
|
||||
}
|
||||
|
||||
func (s *RawSpec) SpecData() metadata.Metadata {
|
||||
func (s *RawSpec) SpecData() map[string]any {
|
||||
return s.Data
|
||||
}
|
||||
|
||||
var _ Spec = &RawSpec{}
|
||||
|
@ -26,11 +26,11 @@ func (s *Spec) SpecRevision() int {
|
||||
return s.Revision
|
||||
}
|
||||
|
||||
func (s *Spec) SpecData() any {
|
||||
return struct {
|
||||
Config *uci.UCI `json:"config"`
|
||||
PostImportCommands []*UCIPostImportCommand `json:"postImportCommands"`
|
||||
}{Config: s.Config, PostImportCommands: s.PostImportCommands}
|
||||
func (s *Spec) SpecData() map[string]any {
|
||||
return map[string]any{
|
||||
"config": s.Config,
|
||||
"postImportCommands": s.PostImportCommands,
|
||||
}
|
||||
}
|
||||
|
||||
func NewSpec() *Spec {
|
||||
@ -38,3 +38,5 @@ func NewSpec() *Spec {
|
||||
PostImportCommands: make([]*UCIPostImportCommand, 0),
|
||||
}
|
||||
}
|
||||
|
||||
var _ spec.Spec = &Spec{}
|
||||
|
Reference in New Issue
Block a user