blob: 7a5e5f38ba5c73d7fb0962dd31f7555945f12653 [file] [log] [blame]
gio3af43942024-04-16 08:13:50 +04001package installer
2
3import (
4 "fmt"
gio09a3e5b2024-04-26 14:11:06 +04005 "html/template"
gio3af43942024-04-16 08:13:50 +04006)
7
8type Release struct {
gio3cdee592024-04-17 10:15:56 +04009 AppInstanceId string `json:"appInstanceId"`
10 Namespace string `json:"namespace"`
11 RepoAddr string `json:"repoAddr"`
12 AppDir string `json:"appDir"`
giof8843412024-05-22 16:38:05 +040013 ImageRegistry string `json:"imageRegistry,omitempty"`
gio3af43942024-04-16 08:13:50 +040014}
15
16type Network struct {
giocdfa3722024-06-13 20:10:14 +040017 Name string `json:"name,omitempty"`
18 IngressClass string `json:"ingressClass,omitempty"`
19 CertificateIssuer string `json:"certificateIssuer,omitempty"`
20 Domain string `json:"domain,omitempty"`
21 AllocatePortAddr string `json:"allocatePortAddr,omitempty"`
22 ReservePortAddr string `json:"reservePortAddr,omitempty"`
23 DeallocatePortAddr string `json:"deallocatePortAddr,omitempty"`
gio3af43942024-04-16 08:13:50 +040024}
25
gioe72b54f2024-04-22 10:44:41 +040026type InfraAppInstanceConfig struct {
27 Id string `json:"id"`
28 AppId string `json:"appId"`
29 Infra InfraConfig `json:"infra"`
30 Release Release `json:"release"`
31 Values map[string]any `json:"values"`
32 Input map[string]any `json:"input"`
gio09a3e5b2024-04-26 14:11:06 +040033 URL string `json:"url"`
34 Help []HelpDocument `json:"help"`
35 Icon template.HTML `json:"icon"`
gioe72b54f2024-04-22 10:44:41 +040036}
37
gio3cdee592024-04-17 10:15:56 +040038type AppInstanceConfig struct {
gio3af43942024-04-16 08:13:50 +040039 Id string `json:"id"`
40 AppId string `json:"appId"`
gioe72b54f2024-04-22 10:44:41 +040041 Env EnvConfig `json:"env"`
gio3cdee592024-04-17 10:15:56 +040042 Release Release `json:"release"`
43 Values map[string]any `json:"values"`
44 Input map[string]any `json:"input"`
gio09a3e5b2024-04-26 14:11:06 +040045 URL string `json:"url"`
Davit Tabidze56f86a42024-04-09 19:15:25 +040046 Help []HelpDocument `json:"help"`
gio09a3e5b2024-04-26 14:11:06 +040047 Icon string `json:"icon"`
gio3af43942024-04-16 08:13:50 +040048}
49
gio3cdee592024-04-17 10:15:56 +040050func (a AppInstanceConfig) InputToValues(schema Schema) map[string]any {
51 ret, err := derivedToConfig(a.Input, schema)
gio3af43942024-04-16 08:13:50 +040052 if err != nil {
gio3cdee592024-04-17 10:15:56 +040053 panic(err)
gio3af43942024-04-16 08:13:50 +040054 }
55 return ret
56}
57
58func deriveValues(values any, schema Schema, networks []Network) (map[string]any, error) {
59 ret := make(map[string]any)
gio44f621b2024-04-29 09:44:38 +040060 for _, f := range schema.Fields() {
61 k := f.Name
62 def := f.Schema
gio3af43942024-04-16 08:13:50 +040063 // TODO(gio): validate that it is map
64 v, ok := values.(map[string]any)[k]
65 // TODO(gio): if missing use default value
66 if !ok {
67 if def.Kind() == KindSSHKey {
68 key, err := NewECDSASSHKeyPair("tmp")
69 if err != nil {
70 return nil, err
71 }
72 ret[k] = map[string]string{
73 "public": string(key.RawAuthorizedKey()),
74 "private": string(key.RawPrivateKey()),
75 }
76 }
77 continue
78 }
79 switch def.Kind() {
80 case KindBoolean:
81 ret[k] = v
82 case KindString:
83 ret[k] = v
84 case KindInt:
85 ret[k] = v
gioefa0ed42024-06-13 12:31:43 +040086 case KindPort:
87 ret[k] = v
gioe72b54f2024-04-22 10:44:41 +040088 case KindArrayString:
89 a, ok := v.([]string)
90 if !ok {
91 return nil, fmt.Errorf("expected string array")
92 }
93 ret[k] = a
gio3af43942024-04-16 08:13:50 +040094 case KindNetwork:
gio4ece99c2024-07-18 11:05:50 +040095 name, ok := v.(string)
96 if !ok {
97 return nil, fmt.Errorf("not a string")
98 }
99 n, err := findNetwork(networks, name)
gio3af43942024-04-16 08:13:50 +0400100 if err != nil {
101 return nil, err
102 }
103 ret[k] = n
gio4ece99c2024-07-18 11:05:50 +0400104 case KindMultiNetwork:
105 vv, ok := v.([]any)
106 if !ok {
107 return nil, fmt.Errorf("not an array")
108 }
109 picked := []Network{}
110 for _, nn := range vv {
111 name, ok := nn.(string)
112 if !ok {
113 return nil, fmt.Errorf("not a string")
114 }
115 n, err := findNetwork(networks, name)
116 if err != nil {
117 return nil, err
118 }
119 picked = append(picked, n)
120 }
121 ret[k] = picked
gio3af43942024-04-16 08:13:50 +0400122 case KindAuth:
123 r, err := deriveValues(v, AuthSchema, networks)
124 if err != nil {
125 return nil, err
126 }
127 ret[k] = r
128 case KindSSHKey:
129 r, err := deriveValues(v, SSHKeySchema, networks)
130 if err != nil {
131 return nil, err
132 }
133 ret[k] = r
134 case KindStruct:
135 r, err := deriveValues(v, def, networks)
136 if err != nil {
137 return nil, err
138 }
139 ret[k] = r
140 default:
141 return nil, fmt.Errorf("Should not reach!")
142 }
143 }
144 return ret, nil
145}
146
147func derivedToConfig(derived map[string]any, schema Schema) (map[string]any, error) {
148 ret := make(map[string]any)
gio44f621b2024-04-29 09:44:38 +0400149 for _, f := range schema.Fields() {
150 k := f.Name
151 def := f.Schema
gio3af43942024-04-16 08:13:50 +0400152 v, ok := derived[k]
153 // TODO(gio): if missing use default value
154 if !ok {
155 continue
156 }
157 switch def.Kind() {
158 case KindBoolean:
159 ret[k] = v
160 case KindString:
161 ret[k] = v
162 case KindInt:
163 ret[k] = v
gioefa0ed42024-06-13 12:31:43 +0400164 case KindPort:
165 ret[k] = v
gioe72b54f2024-04-22 10:44:41 +0400166 case KindArrayString:
167 a, ok := v.([]string)
168 if !ok {
169 return nil, fmt.Errorf("expected string array")
170 }
171 ret[k] = a
gio3af43942024-04-16 08:13:50 +0400172 case KindNetwork:
173 vm, ok := v.(map[string]any)
174 if !ok {
175 return nil, fmt.Errorf("expected map")
176 }
177 name, ok := vm["name"]
178 if !ok {
179 return nil, fmt.Errorf("expected network name")
180 }
181 ret[k] = name
gio4ece99c2024-07-18 11:05:50 +0400182 case KindMultiNetwork:
183 nl, ok := v.([]any)
184 if !ok {
185 return nil, fmt.Errorf("expected map")
186 }
187 names := []string{}
188 for _, n := range nl {
189 i, ok := n.(map[string]any)
190 if !ok {
191 return nil, fmt.Errorf("expected map")
192 }
193 name, ok := i["name"]
194 if !ok {
195 return nil, fmt.Errorf("expected network name")
196 }
197 names = append(names, name.(string))
198 }
199 ret[k] = names
gio3af43942024-04-16 08:13:50 +0400200 case KindAuth:
201 vm, ok := v.(map[string]any)
202 if !ok {
203 return nil, fmt.Errorf("expected map")
204 }
205 r, err := derivedToConfig(vm, AuthSchema)
206 if err != nil {
207 return nil, err
208 }
209 ret[k] = r
210 case KindSSHKey:
211 vm, ok := v.(map[string]any)
212 if !ok {
213 return nil, fmt.Errorf("expected map")
214 }
215 r, err := derivedToConfig(vm, SSHKeySchema)
216 if err != nil {
217 return nil, err
218 }
219 ret[k] = r
220 case KindStruct:
221 vm, ok := v.(map[string]any)
222 if !ok {
223 return nil, fmt.Errorf("expected map")
224 }
225 r, err := derivedToConfig(vm, def)
226 if err != nil {
227 return nil, err
228 }
229 ret[k] = r
230 default:
231 return nil, fmt.Errorf("Should not reach!")
232 }
233 }
234 return ret, nil
235}
236
237func findNetwork(networks []Network, name string) (Network, error) {
238 for _, n := range networks {
239 if n.Name == name {
240 return n, nil
241 }
242 }
243 return Network{}, fmt.Errorf("Network not found: %s", name)
244}