blob: d4dc1a4bfe797966abb63c5f11d615be68a4b823 [file] [log] [blame]
gio561724f2024-11-04 08:37:34 +04001package installer
2
3import (
gio721c0042025-04-03 11:56:36 +04004 "bytes"
5 "encoding/json"
giod78896a2025-04-10 07:42:13 +04006 "fmt"
gio561724f2024-11-04 08:37:34 +04007 "testing"
8
9 "cuelang.org/go/cue/errors"
10)
11
giofc441e32024-11-11 16:26:14 +040012var exposed = `
gio842db3f2025-05-30 11:57:20 +040013input: {
14 key: {
15 private: "asd"
16 public: "qwe"
17 }
18}
giofc441e32024-11-11 16:26:14 +040019service: [{
20 name: "app"
gio561724f2024-11-04 08:37:34 +040021 type: "golang:1.20.0"
22 run: "main.go"
gio4fa7eb32025-04-16 17:23:06 +040023 ingress: [{
gio561724f2024-11-04 08:37:34 +040024 network: "private"
25 subdomain: "testapp"
26 auth: enabled: false
giob6359422025-06-18 13:35:09 +040027 port: name: "web"
gio4fa7eb32025-04-16 17:23:06 +040028 }]
giofc441e32024-11-11 16:26:14 +040029 source: repository: "ssh://foo.bar"
30 ports: [{
31 name: "a"
32 value: 100
33 }, {
34 name: "web"
35 value: 8080
36 }, {
37 name: "b"
38 value: 101
39 }]
40 expose: [{
41 network: "private"
42 subdomain: "1"
43 port: value: 100
44 }, {
45 network: "public"
46 subdomain:"2"
47 port: name: "web"
48 }, {
49 network: "private"
50 subdomain: "3"
51 port: value: 101
gioa1f29472025-05-14 13:05:05 +040052 }],
53 dev: enabled: false
giofc441e32024-11-11 16:26:14 +040054}]
gio561724f2024-11-04 08:37:34 +040055
56postgresql: [{
57 name: "db_1"
giofc441e32024-11-11 16:26:14 +040058 expose: [{
59 network: "private"
60 subdomain: "1"
61 }, {
62 network: "public"
63 subdomain:"2"
64 }, {
65 network: "private"
66 subdomain: "3"
67 }]
gio561724f2024-11-04 08:37:34 +040068}, {
69 name: "db_2"
giofc441e32024-11-11 16:26:14 +040070 expose: [{
71 network: "public"
72 subdomain: "1"
73 }, {
74 network: "private"
75 subdomain:"2"
76 }, {
77 network: "public"
78 subdomain: "3"
79 }]
80}]
gio561724f2024-11-04 08:37:34 +040081
giofc441e32024-11-11 16:26:14 +040082mongodb: [{
83 name: "mdb_1"
84 expose: [{
85 network: "public"
86 subdomain: "1"
87 }, {
88 network: "private"
89 subdomain:"2"
90 }, {
91 network: "public"
92 subdomain: "3"
93 }]
94}, {
95 name: "mdb_2"
96 expose: [{
97 network: "private"
98 subdomain: "1"
99 }, {
100 network: "public"
101 subdomain:"2"
102 }, {
103 network: "private"
104 subdomain: "3"
105 }]
106}]
107`
108
109func TestExposedPorts(t *testing.T) {
110 app, err := NewDodoApp([]byte(exposed))
gio561724f2024-11-04 08:37:34 +0400111 if err != nil {
112 for _, e := range errors.Errors(err) {
113 t.Log(e)
114 }
115 t.Fatal(err)
116 }
gio561724f2024-11-04 08:37:34 +0400117 release := Release{
118 Namespace: "foo",
119 AppInstanceId: "foo-bar",
120 RepoAddr: "ssh://192.168.100.210:22/config",
121 AppDir: "/foo/bar",
122 }
123 keyGen := testKeyGen{}
124 r, err := app.Render(release, env, networks, nil, map[string]any{
giofc441e32024-11-11 16:26:14 +0400125 "managerAddr": "",
126 "appId": "",
127 "sshPrivateKey": "",
128 "port_postgresql_db_1_0": 1,
129 "port_postgresql_db_1_1": 2,
130 "port_postgresql_db_1_2": 3,
131 "port_postgresql_db_2_0": 4,
132 "port_postgresql_db_2_1": 5,
133 "port_postgresql_db_2_2": 6,
134 "port_mongodb_mdb_1_0": 1,
135 "port_mongodb_mdb_1_1": 2,
136 "port_mongodb_mdb_1_2": 3,
137 "port_mongodb_mdb_2_0": 4,
138 "port_mongodb_mdb_2_1": 5,
139 "port_mongodb_mdb_2_2": 6,
140 "port_service_app_0": 7,
141 "port_service_app_1": 8,
142 "port_service_app_2": 9,
gio561724f2024-11-04 08:37:34 +0400143 }, nil, keyGen)
144 if err != nil {
giofc441e32024-11-11 16:26:14 +0400145 t.Fatal(err)
146 }
147 t.Log(string(r.Raw))
148}
149
150const canvas = `
151{
152 "service": [
153 {
154 "type": "nextjs:deno-2.0.0",
155 "name": "app",
156 "source": {
157 "repository": "ssh://d.p.v1.dodo.cloud:62533/myblog",
158 "branch": "master",
159 "rootDir": "/"
160 },
161 "ports": [
162 {
163 "name": "web",
164 "value": 3000,
165 "protocol": "TCP"
166 }
167 ],
168 "env": [
169 {
170 "name": "DODO_POSTGRESQL_DB_CONNECTION_URL"
171 }
172 ],
gio4fa7eb32025-04-16 17:23:06 +0400173 "ingress": [{
giofc441e32024-11-11 16:26:14 +0400174 "network": "Private",
175 "subdomain": "foo",
176 "port": {
177 "name": "web"
178 },
179 "auth": {
180 "enabled": false
181 }
gio4fa7eb32025-04-16 17:23:06 +0400182 }, {
183 "network": "Public",
184 "subdomain": "foo",
185 "port": {
186 "name": "web"
187 },
188 "auth": {
189 "enabled": false
190 }
191 }],
giofc441e32024-11-11 16:26:14 +0400192 "expose": [],
193 "dev": { "enabled": true, "username": "gio" }
194 }
195 ],
196 "volume": [],
197 "postgresql": [
198 {
199 "name": "db",
200 "size": "1Gi",
201 "expose": []
202 }
203 ],
204 "mongodb": []
205}
206`
207
208func TestCanvas(t *testing.T) {
209 app, err := NewDodoApp([]byte(canvas))
210 if err != nil {
gio561724f2024-11-04 08:37:34 +0400211 for _, e := range errors.Errors(err) {
giofc441e32024-11-11 16:26:14 +0400212 t.Log(e)
gio561724f2024-11-04 08:37:34 +0400213 }
214 t.Fatal(err)
215 }
giofc441e32024-11-11 16:26:14 +0400216 release := Release{
217 Namespace: "foo",
218 AppInstanceId: "foo-bar",
219 RepoAddr: "ssh://192.168.100.210:22/config",
220 AppDir: "/foo/bar",
221 }
222 keyGen := testKeyGen{}
223 r, err := app.Render(release, env, networks, nil, map[string]any{
224 "managerAddr": "",
225 "appId": "",
226 "sshPrivateKey": "",
227 }, nil, keyGen)
228 if err != nil {
229 t.Fatal(err)
230 }
gio561724f2024-11-04 08:37:34 +0400231 t.Log(string(r.Raw))
232}
gio721c0042025-04-03 11:56:36 +0400233
giof4344632025-04-08 20:04:35 +0400234const exposeRemoteClusterPrivateNetwork = `
gio721c0042025-04-03 11:56:36 +0400235{
236 "cluster": "remote",
237 "postgresql": [{
238 "name": "db",
239 "size": "1Gi",
240 "expose": [{
241 "network": "Private",
242 "subdomain": "pg"
243 }]
244 }],
245}
246`
247
giof4344632025-04-08 20:04:35 +0400248func TestExposeRemoteClusterPrivateNetwork(t *testing.T) {
gio721c0042025-04-03 11:56:36 +0400249 var buf bytes.Buffer
giof4344632025-04-08 20:04:35 +0400250 if _, err := buf.WriteString(exposeRemoteClusterPrivateNetwork); err != nil {
gio721c0042025-04-03 11:56:36 +0400251 t.Fatal(err)
252 }
253 clusters := []Cluster{{
254 Name: "remote",
255 Kubeconfig: "<KUBECONFIG>",
256 IngressClassName: "<INGRESS_CLASS_NAME>",
257 }}
258 if err := json.NewEncoder(&buf).Encode(struct {
259 Clusters []Cluster `json:"clusters"`
260 }{
261 clusters,
262 }); err != nil {
263 t.Fatal(err)
264 }
265 app, err := NewDodoApp(buf.Bytes())
266 if err != nil {
267 for _, e := range errors.Errors(err) {
268 t.Log(e)
269 }
270 t.Fatal(err)
271 }
272 release := Release{
273 Namespace: "foo",
274 AppInstanceId: "foo-bar",
275 RepoAddr: "ssh://192.168.100.210:22/config",
276 AppDir: "/foo/bar",
277 }
278 keyGen := testKeyGen{}
279 r, err := app.Render(release, env, networks, clusters, map[string]any{
280 "managerAddr": "",
281 "appId": "",
282 "sshPrivateKey": "",
283 "port_postgresql_db_0": 1,
284 "port_postgresql_db_0_cluster": 2,
285 }, nil, keyGen)
286 if err != nil {
287 t.Fatal(err)
288 }
289 t.Log(string(r.Raw))
giod78896a2025-04-10 07:42:13 +0400290 t.Log(fmt.Sprintf("%+v", r.Ports))
gio721c0042025-04-03 11:56:36 +0400291}
giof4344632025-04-08 20:04:35 +0400292
293const exposeRemoteClusterPublicNetwork = `
294{
295 "cluster": "remote",
296 "postgresql": [{
297 "name": "db",
298 "size": "1Gi",
299 "expose": [{
300 "network": "Public",
301 "subdomain": "pg"
302 }]
303 }],
304}
305`
306
307func TestExposeRemoteClusterPublicNetwork(t *testing.T) {
308 var buf bytes.Buffer
309 if _, err := buf.WriteString(exposeRemoteClusterPublicNetwork); err != nil {
310 t.Fatal(err)
311 }
312 clusters := []Cluster{{
313 Name: "remote",
314 Kubeconfig: "<KUBECONFIG>",
315 IngressClassName: "<INGRESS_CLASS_NAME>",
316 }}
317 if err := json.NewEncoder(&buf).Encode(struct {
318 Clusters []Cluster `json:"clusters"`
319 }{
320 clusters,
321 }); err != nil {
322 t.Fatal(err)
323 }
324 app, err := NewDodoApp(buf.Bytes())
325 if err != nil {
326 for _, e := range errors.Errors(err) {
327 t.Log(e)
328 }
329 t.Fatal(err)
330 }
331 release := Release{
332 Namespace: "foo",
333 AppInstanceId: "foo-bar",
334 RepoAddr: "ssh://192.168.100.210:22/config",
335 AppDir: "/foo/bar",
336 }
337 keyGen := testKeyGen{}
338 r, err := app.Render(release, env, networks, clusters, map[string]any{
339 "managerAddr": "",
340 "appId": "",
341 "sshPrivateKey": "",
342 "port_postgresql_db_0": 1,
343 "port_postgresql_db_0_cluster": 2,
344 "port_postgresql_db_0_private": 3,
345 }, nil, keyGen)
346 if err != nil {
347 t.Fatal(err)
348 }
349 t.Log(string(r.Raw))
350}
giof55ab362025-04-11 17:48:17 +0400351
352const exposeSVCRemoteCluster = `
353{
gioa1f29472025-05-14 13:05:05 +0400354 "cluster": "remote",
355 "service": [
356 {
357 "name": "echo",
358 "type": "golang:1.20.0",
359 "source": {
360 "repository": "ssh://foo.bar"
361 },
362 "ports": [
363 {
364 "name": "echo",
365 "value": 9090
366 }
367 ],
368 "expose": [
369 {
370 "port": {
371 "name": "echo"
372 },
373 "network": "Private",
374 "subdomain": "echo"
375 }
376 ],
377 "dev": {
378 "enabled": false
379 }
380 }
381 ]
giof55ab362025-04-11 17:48:17 +0400382}
383`
384
385func TestExposeSVCRemoteCluster(t *testing.T) {
386 var buf bytes.Buffer
387 if _, err := buf.WriteString(exposeSVCRemoteCluster); err != nil {
388 t.Fatal(err)
389 }
390 clusters := []Cluster{{
391 Name: "remote",
392 Kubeconfig: "<KUBECONFIG>",
393 IngressClassName: "<INGRESS_CLASS_NAME>",
394 }}
395 if err := json.NewEncoder(&buf).Encode(struct {
396 Clusters []Cluster `json:"clusters"`
397 }{
398 clusters,
399 }); err != nil {
400 t.Fatal(err)
401 }
402 app, err := NewDodoApp(buf.Bytes())
403 if err != nil {
404 for _, e := range errors.Errors(err) {
405 t.Log(e)
406 }
407 t.Fatal(err)
408 }
409 release := Release{
410 Namespace: "foo",
411 AppInstanceId: "foo-bar",
412 RepoAddr: "ssh://192.168.100.210:22/config",
413 AppDir: "/foo/bar",
414 }
415 keyGen := testKeyGen{}
416 r, err := app.Render(release, env, networks, clusters, map[string]any{
417 "managerAddr": "",
418 "appId": "",
419 "sshPrivateKey": "",
420 "port_service_echo_0": 1,
421 "port_service_echo_0_cluster": 2,
422 }, nil, keyGen)
423 if err != nil {
424 t.Fatal(err)
425 }
426 t.Log(string(r.Raw))
427 t.Log(fmt.Sprintf("%+v", r.Ports))
428}
gioa1f29472025-05-14 13:05:05 +0400429
430const sshCodeServer = `
431{
432 "service": [
433 {
434 "type": "nextjs:deno-2.0.0",
435 "name": "app",
436 "source": {
437 "repository": "ssh://d.p.v1.dodo.cloud:62533/myblog",
438 "branch": "master",
439 "rootDir": "/"
440 },
441 "ports": [
442 {
443 "name": "web",
444 "value": 3000,
445 "protocol": "TCP"
446 }
447 ],
448 "env": [
449 {
450 "name": "DODO_POSTGRESQL_DB_CONNECTION_URL"
451 }
452 ],
453 "ingress": [
454 {
455 "network": "Private",
456 "subdomain": "foo",
457 "port": {
458 "name": "web"
459 },
460 "auth": {
461 "enabled": false
462 }
463 },
464 {
465 "network": "Public",
466 "subdomain": "foo",
467 "port": {
468 "name": "web"
469 },
470 "auth": {
471 "enabled": false
472 }
473 }
474 ],
475 "expose": [{
476 "network": "Public",
477 "subdomain": "foo",
478 "port": {
479 "name": "web"
480 },
481 }],
482 "dev": {
483 "enabled": true,
484 "username": "gio",
485 "codeServer": {
486 "network": "Private",
487 "subdomain": "code"
488 },
489 "ssh": {
490 "network": "Public",
491 "subdomain": "ssh"
492 }
493 }
494 }
495 ],
496 "volume": [],
497 "postgresql": [
498 {
499 "name": "db",
500 "size": "1Gi",
501 "expose": []
502 }
503 ],
504 "mongodb": []
505}
506`
507
508func TestSSHCodeServer(t *testing.T) {
509 app, err := NewDodoApp([]byte(sshCodeServer))
510 if err != nil {
511 for _, e := range errors.Errors(err) {
512 t.Log(e)
513 }
514 t.Fatal(err)
515 }
516 release := Release{
517 Namespace: "foo",
518 AppInstanceId: "foo-bar",
519 RepoAddr: "ssh://192.168.100.210:22/config",
520 AppDir: "/foo/bar",
521 }
522 keyGen := testKeyGen{}
523 r, err := app.Render(release, env, networks, nil, map[string]any{
524 "managerAddr": "",
525 "appId": "",
526 "sshPrivateKey": "",
527 "port_service_app_ssh": 12,
528 "port_service_app_0": 13,
529 }, nil, keyGen)
530 if err != nil {
531 t.Fatal(err)
532 }
533 t.Log(string(r.Raw))
534}
giob1d3bd72025-05-15 07:20:06 +0400535
536const foo = `
537{
538 "service": [
539 {
540 "type": "deno:2.2.0",
541 "name": "qwe",
542 "source": {
543 "repository": "git@github.com:giolekva/dodo-blog.git"
544 },
545 "ports": [
546 {
547 "name": "web",
548 "value": 8080,
549 "protocol": "TCP"
550 }
551 ],
552 "env": [
553 {
554 "name": "DODO_POSTGRESQL_DB_URL"
555 },
556 {
557 "name": "DODO_PORT_WEB"
558 }
559 ],
560 "ingress": [
561 {
562 "network": "Private",
563 "subdomain": "blog",
564 "port": {
565 "name": "web"
566 },
567 "auth": {
568 "enabled": false
569 }
570 }
571 ],
gio6ce44812025-05-17 07:31:54 +0400572 "expose": [
573 {
574 "network": "Private",
575 "subdomain": "blog",
576 "port": {
577 "name": "web"
578 }
579 }
580 ],
giob1d3bd72025-05-15 07:20:06 +0400581 "preBuildCommands": [],
582 "dev": {
583 "enabled": true,
584 "username": "gio",
585 "codeServer": {
586 "network": "Private",
587 "subdomain": "code"
588 },
589 "ssh": {
590 "network": "Public",
591 "subdomain": "code"
592 }
593 }
594 }
595 ],
596 "volume": [],
597 "postgresql": [
598 {
599 "name": "db",
600 "size": "1Gi",
gio6ce44812025-05-17 07:31:54 +0400601 "expose": [
602 {
603 "network": "Private",
604 "subdomain": "pg"
605 }
606 ]
giob1d3bd72025-05-15 07:20:06 +0400607 }
608 ],
609 "mongodb": []
610}
611`
612
613func TestFoo(t *testing.T) {
614 app, err := NewDodoApp([]byte(foo))
615 if err != nil {
616 for _, e := range errors.Errors(err) {
617 t.Log(e)
618 }
619 t.Fatal(err)
620 }
621 release := Release{
622 Namespace: "foo",
623 AppInstanceId: "foo-bar",
624 RepoAddr: "ssh://192.168.100.210:22/config",
625 AppDir: "/foo/bar",
626 }
627 keyGen := testKeyGen{}
628 r, err := app.Render(release, env, networks, nil, map[string]any{
629 "managerAddr": "",
630 "appId": "",
631 "sshPrivateKey": "",
gio6ce44812025-05-17 07:31:54 +0400632 "port_service_qwe_ssh": 1,
633 "port_service_qwe_0": 2,
634 "port_postgresql_db_0": 3,
giob1d3bd72025-05-15 07:20:06 +0400635 }, nil, keyGen)
636 if err != nil {
637 t.Fatal(err)
638 }
gio6ce44812025-05-17 07:31:54 +0400639 access, err := json.Marshal(r.Access)
640 if err != nil {
641 t.Fatal(err)
642 }
643 t.Log(string(access))
giob1d3bd72025-05-15 07:20:06 +0400644}
gioe65d9a92025-06-19 09:02:32 +0400645
646const sketch = `
647{
gio7f293f32025-06-24 09:03:46 +0400648 "agent": [
649 {
650 "type": "sketch:latest",
651 "name": "dev",
652 "geminiApiKey": "foo",
653 "ports": [
gioe65d9a92025-06-19 09:02:32 +0400654 {
gio7f293f32025-06-24 09:03:46 +0400655 "name": "agent",
656 "value": 2001,
657 "protocol": "TCP"
658 },
659 {
660 "name": "p8080",
661 "value": 8080,
662 "protocol": "TCP"
663 },
664 {
665 "name": "p8081",
666 "value": 8081,
667 "protocol": "TCP"
668 },
669 {
670 "name": "p8082",
671 "value": 8082,
672 "protocol": "TCP"
673 },
674 {
675 "name": "p8083",
676 "value": 8083,
677 "protocol": "TCP"
678 },
679 {
680 "name": "p8084",
681 "value": 8084,
682 "protocol": "TCP"
gioe65d9a92025-06-19 09:02:32 +0400683 }
gio7f293f32025-06-24 09:03:46 +0400684 ]
685 }
686 ]
gioe65d9a92025-06-19 09:02:32 +0400687}
688`
689
690func TestSketch(t *testing.T) {
691 app, err := NewDodoApp([]byte(sketch))
692 if err != nil {
693 for _, e := range errors.Errors(err) {
694 t.Log(e)
695 }
696 t.Fatal(err)
697 }
698 release := Release{
699 Namespace: "foo",
700 AppInstanceId: "foo-bar",
701 RepoAddr: "ssh://192.168.100.210:22/config",
702 AppDir: "/foo/bar",
703 }
704 keyGen := testKeyGen{}
705 r, err := app.Render(release, env, networks, nil, map[string]any{
706 "managerAddr": "",
707 "appId": "",
708 "geminiApiKey": "dev",
709 }, nil, keyGen)
710 if err != nil {
711 t.Fatal(err)
712 }
713 t.Log(string(r.Raw))
714}
715
716const sketchGlobalGeminiApiKey = `
717{
718 "agent": [
719 {
720 "type": "sketch:latest",
721 "name": "dev",
722 }
723 ],
724}
725`
726
727func TestSketchGlobalGeminiApiKey(t *testing.T) {
728 app, err := NewDodoApp([]byte(sketchGlobalGeminiApiKey))
729 if err != nil {
730 for _, e := range errors.Errors(err) {
731 t.Log(e)
732 }
733 t.Fatal(err)
734 }
735 release := Release{
736 Namespace: "foo",
737 AppInstanceId: "foo-bar",
738 RepoAddr: "ssh://192.168.100.210:22/config",
739 AppDir: "/foo/bar",
740 }
741 keyGen := testKeyGen{}
742 r, err := app.Render(release, env, networks, nil, map[string]any{
743 "managerAddr": "",
744 "appId": "",
745 "geminiApiKey": "dev",
746 }, nil, keyGen)
747 if err != nil {
748 t.Fatal(err)
749 }
750 t.Log(string(r.Raw))
751}