blob: add5cebfad5039e40a3ae4cce52a40f28c191b26 [file] [log] [blame]
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +04001package installer
2
3import (
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +04004 "fmt"
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +04005
6 "cuelang.org/go/cue"
7 "cuelang.org/go/cue/cuecontext"
8)
9
10type Kind int
11
12const (
gioe72b54f2024-04-22 10:44:41 +040013 KindBoolean Kind = 0
14 KindInt = 7
15 KindString = 1
16 KindStruct = 2
17 KindNetwork = 3
18 KindAuth = 5
19 KindSSHKey = 6
20 KindNumber = 4
21 KindArrayString = 8
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040022)
23
24type Schema interface {
25 Kind() Kind
26 Fields() map[string]Schema
27}
28
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040029var AuthSchema Schema = structSchema{
30 fields: map[string]Schema{
31 "enabled": basicSchema{KindBoolean},
32 "groups": basicSchema{KindString},
33 },
34}
35
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +040036var SSHKeySchema Schema = structSchema{
37 fields: map[string]Schema{
38 "public": basicSchema{KindString},
39 "private": basicSchema{KindString},
40 },
41}
42
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040043const networkSchema = `
44#Network: {
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +040045 name: string
46 ingressClass: string
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040047 certificateIssuer: string | *""
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +040048 domain: string
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +040049 allocatePortAddr: string
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040050}
51
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040052value: { %s }
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040053`
54
55func isNetwork(v cue.Value) bool {
56 if v.Value().Kind() != cue.StructKind {
57 return false
58 }
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040059 s := fmt.Sprintf(networkSchema, fmt.Sprintf("%#v", v))
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040060 c := cuecontext.New()
61 u := c.CompileString(s)
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040062 network := u.LookupPath(cue.ParsePath("#Network"))
63 vv := u.LookupPath(cue.ParsePath("value"))
64 if err := network.Subsume(vv); err == nil {
65 return true
66 }
67 return false
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040068}
69
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040070const authSchema = `
71#Auth: {
72 enabled: bool | false
73 groups: string | *""
74}
75
76value: { %s }
77`
78
79func isAuth(v cue.Value) bool {
80 if v.Value().Kind() != cue.StructKind {
81 return false
82 }
83 s := fmt.Sprintf(authSchema, fmt.Sprintf("%#v", v))
84 c := cuecontext.New()
85 u := c.CompileString(s)
86 auth := u.LookupPath(cue.ParsePath("#Auth"))
87 vv := u.LookupPath(cue.ParsePath("value"))
88 if err := auth.Subsume(vv); err == nil {
89 return true
90 }
91 return false
92}
93
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +040094const sshKeySchema = `
95#SSHKey: {
96 public: string
97 private: string
98}
99
100value: { %s }
101`
102
103func isSSHKey(v cue.Value) bool {
104 if v.Value().Kind() != cue.StructKind {
105 return false
106 }
107 s := fmt.Sprintf(sshKeySchema, fmt.Sprintf("%#v", v))
108 c := cuecontext.New()
109 u := c.CompileString(s)
110 sshKey := u.LookupPath(cue.ParsePath("#SSHKey"))
111 vv := u.LookupPath(cue.ParsePath("value"))
112 if err := sshKey.Subsume(vv); err == nil {
113 return true
114 }
115 return false
116}
117
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400118type basicSchema struct {
119 kind Kind
120}
121
122func (s basicSchema) Kind() Kind {
123 return s.kind
124}
125
126func (s basicSchema) Fields() map[string]Schema {
127 return nil
128}
129
130type structSchema struct {
131 fields map[string]Schema
132}
133
134func (s structSchema) Kind() Kind {
135 return KindStruct
136}
137
138func (s structSchema) Fields() map[string]Schema {
139 return s.fields
140}
141
142func NewCueSchema(v cue.Value) (Schema, error) {
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400143 switch v.IncompleteKind() {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400144 case cue.StringKind:
145 return basicSchema{KindString}, nil
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400146 case cue.BoolKind:
147 return basicSchema{KindBoolean}, nil
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400148 case cue.NumberKind:
149 return basicSchema{KindNumber}, nil
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400150 case cue.IntKind:
151 return basicSchema{KindInt}, nil
gioe72b54f2024-04-22 10:44:41 +0400152 case cue.ListKind:
153 return basicSchema{KindArrayString}, nil
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400154 case cue.StructKind:
155 if isNetwork(v) {
156 return basicSchema{KindNetwork}, nil
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400157 } else if isAuth(v) {
158 return basicSchema{KindAuth}, nil
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +0400159 } else if isSSHKey(v) {
160 return basicSchema{KindSSHKey}, nil
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400161 }
162 s := structSchema{make(map[string]Schema)}
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400163 f, err := v.Fields(cue.Schema())
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400164 if err != nil {
165 return nil, err
166 }
167 for f.Next() {
168 scm, err := NewCueSchema(f.Value())
169 if err != nil {
170 return nil, err
171 }
172 s.fields[f.Selector().String()] = scm
173 }
174 return s, nil
175 default:
176 return nil, fmt.Errorf("SHOULD NOT REACH!")
177 }
178}