blob: 8ddf73f3b6d382d229369dc99006a03a20da3fbf [file] [log] [blame]
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +04001package installer
2
3import (
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +04004 "fmt"
gioefa0ed42024-06-13 12:31:43 +04005 "strings"
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +04006
7 "cuelang.org/go/cue"
8 "cuelang.org/go/cue/cuecontext"
9)
10
11type Kind int
12
13const (
gioe72b54f2024-04-22 10:44:41 +040014 KindBoolean Kind = 0
15 KindInt = 7
16 KindString = 1
17 KindStruct = 2
18 KindNetwork = 3
19 KindAuth = 5
20 KindSSHKey = 6
21 KindNumber = 4
22 KindArrayString = 8
gioefa0ed42024-06-13 12:31:43 +040023 KindPort = 9
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040024)
25
gio44f621b2024-04-29 09:44:38 +040026type Field struct {
27 Name string
28 Schema Schema
29}
30
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040031type Schema interface {
gio44f621b2024-04-29 09:44:38 +040032 Name() string
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040033 Kind() Kind
gio44f621b2024-04-29 09:44:38 +040034 Fields() []Field
35 Advanced() bool
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040036}
37
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040038var AuthSchema Schema = structSchema{
gio44f621b2024-04-29 09:44:38 +040039 name: "Auth",
40 fields: []Field{
41 Field{"enabled", basicSchema{"Enabled", KindBoolean, false}},
42 Field{"groups", basicSchema{"Groups", KindString, false}},
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040043 },
gio44f621b2024-04-29 09:44:38 +040044 advanced: false,
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040045}
46
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +040047var SSHKeySchema Schema = structSchema{
gio44f621b2024-04-29 09:44:38 +040048 name: "SSH Key",
49 fields: []Field{
50 Field{"public", basicSchema{"Public Key", KindString, false}},
51 Field{"private", basicSchema{"Private Key", KindString, false}},
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +040052 },
gio44f621b2024-04-29 09:44:38 +040053 advanced: true,
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +040054}
55
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040056const networkSchema = `
57#Network: {
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +040058 name: string
59 ingressClass: string
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040060 certificateIssuer: string | *""
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +040061 domain: string
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +040062 allocatePortAddr: string
gioefa0ed42024-06-13 12:31:43 +040063 reservePortAddr: string
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040064}
65
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040066value: { %s }
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040067`
68
69func isNetwork(v cue.Value) bool {
70 if v.Value().Kind() != cue.StructKind {
71 return false
72 }
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040073 s := fmt.Sprintf(networkSchema, fmt.Sprintf("%#v", v))
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040074 c := cuecontext.New()
75 u := c.CompileString(s)
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040076 network := u.LookupPath(cue.ParsePath("#Network"))
77 vv := u.LookupPath(cue.ParsePath("value"))
78 if err := network.Subsume(vv); err == nil {
79 return true
80 }
81 return false
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040082}
83
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040084const authSchema = `
85#Auth: {
86 enabled: bool | false
87 groups: string | *""
88}
89
90value: { %s }
91`
92
93func isAuth(v cue.Value) bool {
94 if v.Value().Kind() != cue.StructKind {
95 return false
96 }
97 s := fmt.Sprintf(authSchema, fmt.Sprintf("%#v", v))
98 c := cuecontext.New()
99 u := c.CompileString(s)
100 auth := u.LookupPath(cue.ParsePath("#Auth"))
101 vv := u.LookupPath(cue.ParsePath("value"))
102 if err := auth.Subsume(vv); err == nil {
103 return true
104 }
105 return false
106}
107
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +0400108const sshKeySchema = `
109#SSHKey: {
110 public: string
111 private: string
112}
113
114value: { %s }
115`
116
117func isSSHKey(v cue.Value) bool {
118 if v.Value().Kind() != cue.StructKind {
119 return false
120 }
121 s := fmt.Sprintf(sshKeySchema, fmt.Sprintf("%#v", v))
122 c := cuecontext.New()
123 u := c.CompileString(s)
124 sshKey := u.LookupPath(cue.ParsePath("#SSHKey"))
125 vv := u.LookupPath(cue.ParsePath("value"))
126 if err := sshKey.Subsume(vv); err == nil {
127 return true
128 }
129 return false
130}
131
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400132type basicSchema struct {
gio44f621b2024-04-29 09:44:38 +0400133 name string
134 kind Kind
135 advanced bool
136}
137
138func (s basicSchema) Name() string {
139 return s.name
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400140}
141
142func (s basicSchema) Kind() Kind {
143 return s.kind
144}
145
gio44f621b2024-04-29 09:44:38 +0400146func (s basicSchema) Fields() []Field {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400147 return nil
148}
149
gio44f621b2024-04-29 09:44:38 +0400150func (s basicSchema) Advanced() bool {
151 return s.advanced
152}
153
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400154type structSchema struct {
gio44f621b2024-04-29 09:44:38 +0400155 name string
156 fields []Field
157 advanced bool
158}
159
160func (s structSchema) Name() string {
161 return s.name
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400162}
163
164func (s structSchema) Kind() Kind {
165 return KindStruct
166}
167
gio44f621b2024-04-29 09:44:38 +0400168func (s structSchema) Fields() []Field {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400169 return s.fields
170}
171
gio44f621b2024-04-29 09:44:38 +0400172func (s structSchema) Advanced() bool {
173 return s.advanced
174}
175
176func NewCueSchema(name string, v cue.Value) (Schema, error) {
177 nameAttr := v.Attribute("name")
178 if nameAttr.Err() == nil {
179 name = nameAttr.Contents()
180 }
gioefa0ed42024-06-13 12:31:43 +0400181 role := ""
182 roleAttr := v.Attribute("role")
183 if roleAttr.Err() == nil {
184 role = strings.ToLower(roleAttr.Contents())
185 }
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400186 switch v.IncompleteKind() {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400187 case cue.StringKind:
gio44f621b2024-04-29 09:44:38 +0400188 return basicSchema{name, KindString, false}, nil
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400189 case cue.BoolKind:
gio44f621b2024-04-29 09:44:38 +0400190 return basicSchema{name, KindBoolean, false}, nil
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400191 case cue.NumberKind:
gio44f621b2024-04-29 09:44:38 +0400192 return basicSchema{name, KindNumber, false}, nil
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400193 case cue.IntKind:
gioefa0ed42024-06-13 12:31:43 +0400194 if role == "port" {
195 return basicSchema{name, KindPort, true}, nil
196 } else {
197 return basicSchema{name, KindInt, false}, nil
198 }
gioe72b54f2024-04-22 10:44:41 +0400199 case cue.ListKind:
gio44f621b2024-04-29 09:44:38 +0400200 return basicSchema{name, KindArrayString, false}, nil
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400201 case cue.StructKind:
202 if isNetwork(v) {
gio44f621b2024-04-29 09:44:38 +0400203 return basicSchema{name, KindNetwork, false}, nil
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400204 } else if isAuth(v) {
gio44f621b2024-04-29 09:44:38 +0400205 return basicSchema{name, KindAuth, false}, nil
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +0400206 } else if isSSHKey(v) {
gio44f621b2024-04-29 09:44:38 +0400207 return basicSchema{name, KindSSHKey, true}, nil
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400208 }
gio44f621b2024-04-29 09:44:38 +0400209 s := structSchema{name, make([]Field, 0), false}
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400210 f, err := v.Fields(cue.Schema())
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400211 if err != nil {
212 return nil, err
213 }
214 for f.Next() {
gio44f621b2024-04-29 09:44:38 +0400215 scm, err := NewCueSchema(f.Selector().String(), f.Value())
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400216 if err != nil {
217 return nil, err
218 }
gio44f621b2024-04-29 09:44:38 +0400219 s.fields = append(s.fields, Field{f.Selector().String(), scm})
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400220 }
221 return s, nil
222 default:
223 return nil, fmt.Errorf("SHOULD NOT REACH!")
224 }
225}