blob: a0acfc345cb0130a4a24db97307a8f3e38b3b265 [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
gio44f621b2024-04-29 09:44:38 +040024type Field struct {
25 Name string
26 Schema Schema
27}
28
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040029type Schema interface {
gio44f621b2024-04-29 09:44:38 +040030 Name() string
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040031 Kind() Kind
gio44f621b2024-04-29 09:44:38 +040032 Fields() []Field
33 Advanced() bool
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040034}
35
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040036var AuthSchema Schema = structSchema{
gio44f621b2024-04-29 09:44:38 +040037 name: "Auth",
38 fields: []Field{
39 Field{"enabled", basicSchema{"Enabled", KindBoolean, false}},
40 Field{"groups", basicSchema{"Groups", KindString, false}},
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040041 },
gio44f621b2024-04-29 09:44:38 +040042 advanced: false,
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040043}
44
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +040045var SSHKeySchema Schema = structSchema{
gio44f621b2024-04-29 09:44:38 +040046 name: "SSH Key",
47 fields: []Field{
48 Field{"public", basicSchema{"Public Key", KindString, false}},
49 Field{"private", basicSchema{"Private Key", KindString, false}},
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +040050 },
gio44f621b2024-04-29 09:44:38 +040051 advanced: true,
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +040052}
53
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040054const networkSchema = `
55#Network: {
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +040056 name: string
57 ingressClass: string
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040058 certificateIssuer: string | *""
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +040059 domain: string
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +040060 allocatePortAddr: string
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040061}
62
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040063value: { %s }
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040064`
65
66func isNetwork(v cue.Value) bool {
67 if v.Value().Kind() != cue.StructKind {
68 return false
69 }
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040070 s := fmt.Sprintf(networkSchema, fmt.Sprintf("%#v", v))
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040071 c := cuecontext.New()
72 u := c.CompileString(s)
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040073 network := u.LookupPath(cue.ParsePath("#Network"))
74 vv := u.LookupPath(cue.ParsePath("value"))
75 if err := network.Subsume(vv); err == nil {
76 return true
77 }
78 return false
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040079}
80
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040081const authSchema = `
82#Auth: {
83 enabled: bool | false
84 groups: string | *""
85}
86
87value: { %s }
88`
89
90func isAuth(v cue.Value) bool {
91 if v.Value().Kind() != cue.StructKind {
92 return false
93 }
94 s := fmt.Sprintf(authSchema, fmt.Sprintf("%#v", v))
95 c := cuecontext.New()
96 u := c.CompileString(s)
97 auth := u.LookupPath(cue.ParsePath("#Auth"))
98 vv := u.LookupPath(cue.ParsePath("value"))
99 if err := auth.Subsume(vv); err == nil {
100 return true
101 }
102 return false
103}
104
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +0400105const sshKeySchema = `
106#SSHKey: {
107 public: string
108 private: string
109}
110
111value: { %s }
112`
113
114func isSSHKey(v cue.Value) bool {
115 if v.Value().Kind() != cue.StructKind {
116 return false
117 }
118 s := fmt.Sprintf(sshKeySchema, fmt.Sprintf("%#v", v))
119 c := cuecontext.New()
120 u := c.CompileString(s)
121 sshKey := u.LookupPath(cue.ParsePath("#SSHKey"))
122 vv := u.LookupPath(cue.ParsePath("value"))
123 if err := sshKey.Subsume(vv); err == nil {
124 return true
125 }
126 return false
127}
128
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400129type basicSchema struct {
gio44f621b2024-04-29 09:44:38 +0400130 name string
131 kind Kind
132 advanced bool
133}
134
135func (s basicSchema) Name() string {
136 return s.name
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400137}
138
139func (s basicSchema) Kind() Kind {
140 return s.kind
141}
142
gio44f621b2024-04-29 09:44:38 +0400143func (s basicSchema) Fields() []Field {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400144 return nil
145}
146
gio44f621b2024-04-29 09:44:38 +0400147func (s basicSchema) Advanced() bool {
148 return s.advanced
149}
150
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400151type structSchema struct {
gio44f621b2024-04-29 09:44:38 +0400152 name string
153 fields []Field
154 advanced bool
155}
156
157func (s structSchema) Name() string {
158 return s.name
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400159}
160
161func (s structSchema) Kind() Kind {
162 return KindStruct
163}
164
gio44f621b2024-04-29 09:44:38 +0400165func (s structSchema) Fields() []Field {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400166 return s.fields
167}
168
gio44f621b2024-04-29 09:44:38 +0400169func (s structSchema) Advanced() bool {
170 return s.advanced
171}
172
173func NewCueSchema(name string, v cue.Value) (Schema, error) {
174 nameAttr := v.Attribute("name")
175 if nameAttr.Err() == nil {
176 name = nameAttr.Contents()
177 }
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400178 switch v.IncompleteKind() {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400179 case cue.StringKind:
gio44f621b2024-04-29 09:44:38 +0400180 return basicSchema{name, KindString, false}, nil
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400181 case cue.BoolKind:
gio44f621b2024-04-29 09:44:38 +0400182 return basicSchema{name, KindBoolean, false}, nil
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400183 case cue.NumberKind:
gio44f621b2024-04-29 09:44:38 +0400184 return basicSchema{name, KindNumber, false}, nil
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400185 case cue.IntKind:
gio44f621b2024-04-29 09:44:38 +0400186 return basicSchema{name, KindInt, false}, nil
gioe72b54f2024-04-22 10:44:41 +0400187 case cue.ListKind:
gio44f621b2024-04-29 09:44:38 +0400188 return basicSchema{name, KindArrayString, false}, nil
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400189 case cue.StructKind:
190 if isNetwork(v) {
gio44f621b2024-04-29 09:44:38 +0400191 return basicSchema{name, KindNetwork, false}, nil
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400192 } else if isAuth(v) {
gio44f621b2024-04-29 09:44:38 +0400193 return basicSchema{name, KindAuth, false}, nil
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +0400194 } else if isSSHKey(v) {
gio44f621b2024-04-29 09:44:38 +0400195 return basicSchema{name, KindSSHKey, true}, nil
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400196 }
gio44f621b2024-04-29 09:44:38 +0400197 s := structSchema{name, make([]Field, 0), false}
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400198 f, err := v.Fields(cue.Schema())
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400199 if err != nil {
200 return nil, err
201 }
202 for f.Next() {
gio44f621b2024-04-29 09:44:38 +0400203 scm, err := NewCueSchema(f.Selector().String(), f.Value())
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400204 if err != nil {
205 return nil, err
206 }
gio44f621b2024-04-29 09:44:38 +0400207 s.fields = append(s.fields, Field{f.Selector().String(), scm})
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400208 }
209 return s, nil
210 default:
211 return nil, fmt.Errorf("SHOULD NOT REACH!")
212 }
213}