blob: 943ef8a13ca8b64c106a64db3785c31d5321661b [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
giocdfa3722024-06-13 20:10:14 +040064 deallocatePortAddr: string
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040065}
66
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040067value: { %s }
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040068`
69
70func isNetwork(v cue.Value) bool {
71 if v.Value().Kind() != cue.StructKind {
72 return false
73 }
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040074 s := fmt.Sprintf(networkSchema, fmt.Sprintf("%#v", v))
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040075 c := cuecontext.New()
76 u := c.CompileString(s)
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040077 network := u.LookupPath(cue.ParsePath("#Network"))
78 vv := u.LookupPath(cue.ParsePath("value"))
79 if err := network.Subsume(vv); err == nil {
80 return true
81 }
82 return false
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040083}
84
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040085const authSchema = `
86#Auth: {
87 enabled: bool | false
88 groups: string | *""
89}
90
91value: { %s }
92`
93
94func isAuth(v cue.Value) bool {
95 if v.Value().Kind() != cue.StructKind {
96 return false
97 }
98 s := fmt.Sprintf(authSchema, fmt.Sprintf("%#v", v))
99 c := cuecontext.New()
100 u := c.CompileString(s)
101 auth := u.LookupPath(cue.ParsePath("#Auth"))
102 vv := u.LookupPath(cue.ParsePath("value"))
103 if err := auth.Subsume(vv); err == nil {
104 return true
105 }
106 return false
107}
108
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +0400109const sshKeySchema = `
110#SSHKey: {
111 public: string
112 private: string
113}
114
115value: { %s }
116`
117
118func isSSHKey(v cue.Value) bool {
119 if v.Value().Kind() != cue.StructKind {
120 return false
121 }
122 s := fmt.Sprintf(sshKeySchema, fmt.Sprintf("%#v", v))
123 c := cuecontext.New()
124 u := c.CompileString(s)
125 sshKey := u.LookupPath(cue.ParsePath("#SSHKey"))
126 vv := u.LookupPath(cue.ParsePath("value"))
127 if err := sshKey.Subsume(vv); err == nil {
128 return true
129 }
130 return false
131}
132
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400133type basicSchema struct {
gio44f621b2024-04-29 09:44:38 +0400134 name string
135 kind Kind
136 advanced bool
137}
138
139func (s basicSchema) Name() string {
140 return s.name
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400141}
142
143func (s basicSchema) Kind() Kind {
144 return s.kind
145}
146
gio44f621b2024-04-29 09:44:38 +0400147func (s basicSchema) Fields() []Field {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400148 return nil
149}
150
gio44f621b2024-04-29 09:44:38 +0400151func (s basicSchema) Advanced() bool {
152 return s.advanced
153}
154
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400155type structSchema struct {
gio44f621b2024-04-29 09:44:38 +0400156 name string
157 fields []Field
158 advanced bool
159}
160
161func (s structSchema) Name() string {
162 return s.name
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400163}
164
165func (s structSchema) Kind() Kind {
166 return KindStruct
167}
168
gio44f621b2024-04-29 09:44:38 +0400169func (s structSchema) Fields() []Field {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400170 return s.fields
171}
172
gio44f621b2024-04-29 09:44:38 +0400173func (s structSchema) Advanced() bool {
174 return s.advanced
175}
176
177func NewCueSchema(name string, v cue.Value) (Schema, error) {
178 nameAttr := v.Attribute("name")
179 if nameAttr.Err() == nil {
180 name = nameAttr.Contents()
181 }
gioefa0ed42024-06-13 12:31:43 +0400182 role := ""
183 roleAttr := v.Attribute("role")
184 if roleAttr.Err() == nil {
185 role = strings.ToLower(roleAttr.Contents())
186 }
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400187 switch v.IncompleteKind() {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400188 case cue.StringKind:
gio44f621b2024-04-29 09:44:38 +0400189 return basicSchema{name, KindString, false}, nil
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400190 case cue.BoolKind:
gio44f621b2024-04-29 09:44:38 +0400191 return basicSchema{name, KindBoolean, false}, nil
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400192 case cue.NumberKind:
gio44f621b2024-04-29 09:44:38 +0400193 return basicSchema{name, KindNumber, false}, nil
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400194 case cue.IntKind:
gioefa0ed42024-06-13 12:31:43 +0400195 if role == "port" {
196 return basicSchema{name, KindPort, true}, nil
197 } else {
198 return basicSchema{name, KindInt, false}, nil
199 }
gioe72b54f2024-04-22 10:44:41 +0400200 case cue.ListKind:
gio44f621b2024-04-29 09:44:38 +0400201 return basicSchema{name, KindArrayString, false}, nil
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400202 case cue.StructKind:
203 if isNetwork(v) {
gio44f621b2024-04-29 09:44:38 +0400204 return basicSchema{name, KindNetwork, false}, nil
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400205 } else if isAuth(v) {
gio44f621b2024-04-29 09:44:38 +0400206 return basicSchema{name, KindAuth, false}, nil
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +0400207 } else if isSSHKey(v) {
gio44f621b2024-04-29 09:44:38 +0400208 return basicSchema{name, KindSSHKey, true}, nil
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400209 }
gio44f621b2024-04-29 09:44:38 +0400210 s := structSchema{name, make([]Field, 0), false}
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400211 f, err := v.Fields(cue.Schema())
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400212 if err != nil {
213 return nil, err
214 }
215 for f.Next() {
gio44f621b2024-04-29 09:44:38 +0400216 scm, err := NewCueSchema(f.Selector().String(), f.Value())
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400217 if err != nil {
218 return nil, err
219 }
gio44f621b2024-04-29 09:44:38 +0400220 s.fields = append(s.fields, Field{f.Selector().String(), scm})
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400221 }
222 return s, nil
223 default:
224 return nil, fmt.Errorf("SHOULD NOT REACH!")
225 }
226}