blob: de2617395ac4625d23892f544dee78e0f1abf76c [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 (
13 KindBoolean Kind = 0
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +040014 KindInt = 7
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040015 KindString = 1
16 KindStruct = 2
17 KindNetwork = 3
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040018 KindAuth = 5
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +040019 KindSSHKey = 6
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040020 KindNumber = 4
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040021)
22
23type Schema interface {
24 Kind() Kind
25 Fields() map[string]Schema
26}
27
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040028var AuthSchema Schema = structSchema{
29 fields: map[string]Schema{
30 "enabled": basicSchema{KindBoolean},
31 "groups": basicSchema{KindString},
32 },
33}
34
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +040035var SSHKeySchema Schema = structSchema{
36 fields: map[string]Schema{
37 "public": basicSchema{KindString},
38 "private": basicSchema{KindString},
39 },
40}
41
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040042const networkSchema = `
43#Network: {
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +040044 name: string
45 ingressClass: string
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040046 certificateIssuer: string | *""
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +040047 domain: string
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +040048 allocatePortAddr: string
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040049}
50
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040051value: { %s }
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040052`
53
54func isNetwork(v cue.Value) bool {
55 if v.Value().Kind() != cue.StructKind {
56 return false
57 }
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040058 s := fmt.Sprintf(networkSchema, fmt.Sprintf("%#v", v))
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040059 c := cuecontext.New()
60 u := c.CompileString(s)
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040061 network := u.LookupPath(cue.ParsePath("#Network"))
62 vv := u.LookupPath(cue.ParsePath("value"))
63 if err := network.Subsume(vv); err == nil {
64 return true
65 }
66 return false
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040067}
68
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +040069const authSchema = `
70#Auth: {
71 enabled: bool | false
72 groups: string | *""
73}
74
75value: { %s }
76`
77
78func isAuth(v cue.Value) bool {
79 if v.Value().Kind() != cue.StructKind {
80 return false
81 }
82 s := fmt.Sprintf(authSchema, fmt.Sprintf("%#v", v))
83 c := cuecontext.New()
84 u := c.CompileString(s)
85 auth := u.LookupPath(cue.ParsePath("#Auth"))
86 vv := u.LookupPath(cue.ParsePath("value"))
87 if err := auth.Subsume(vv); err == nil {
88 return true
89 }
90 return false
91}
92
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +040093const sshKeySchema = `
94#SSHKey: {
95 public: string
96 private: string
97}
98
99value: { %s }
100`
101
102func isSSHKey(v cue.Value) bool {
103 if v.Value().Kind() != cue.StructKind {
104 return false
105 }
106 s := fmt.Sprintf(sshKeySchema, fmt.Sprintf("%#v", v))
107 c := cuecontext.New()
108 u := c.CompileString(s)
109 sshKey := u.LookupPath(cue.ParsePath("#SSHKey"))
110 vv := u.LookupPath(cue.ParsePath("value"))
111 if err := sshKey.Subsume(vv); err == nil {
112 return true
113 }
114 return false
115}
116
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400117type basicSchema struct {
118 kind Kind
119}
120
121func (s basicSchema) Kind() Kind {
122 return s.kind
123}
124
125func (s basicSchema) Fields() map[string]Schema {
126 return nil
127}
128
129type structSchema struct {
130 fields map[string]Schema
131}
132
133func (s structSchema) Kind() Kind {
134 return KindStruct
135}
136
137func (s structSchema) Fields() map[string]Schema {
138 return s.fields
139}
140
141func NewCueSchema(v cue.Value) (Schema, error) {
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400142 switch v.IncompleteKind() {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400143 case cue.StringKind:
144 return basicSchema{KindString}, nil
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400145 case cue.BoolKind:
146 return basicSchema{KindBoolean}, nil
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400147 case cue.NumberKind:
148 return basicSchema{KindNumber}, nil
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400149 case cue.IntKind:
150 return basicSchema{KindInt}, nil
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400151 case cue.StructKind:
152 if isNetwork(v) {
153 return basicSchema{KindNetwork}, nil
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400154 } else if isAuth(v) {
155 return basicSchema{KindAuth}, nil
Giorgi Lekveishvilib6a58062024-04-02 16:49:19 +0400156 } else if isSSHKey(v) {
157 return basicSchema{KindSSHKey}, nil
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400158 }
159 s := structSchema{make(map[string]Schema)}
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400160 f, err := v.Fields(cue.Schema())
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400161 if err != nil {
162 return nil, err
163 }
164 for f.Next() {
165 scm, err := NewCueSchema(f.Value())
166 if err != nil {
167 return nil, err
168 }
169 s.fields[f.Selector().String()] = scm
170 }
171 return s, nil
172 default:
173 return nil, fmt.Errorf("SHOULD NOT REACH!")
174 }
175}