DodoApp: Implement dev proxy mode

With dev proxy user can substitute any service with their own local
machine. In which case dodo will run proxy server on the platform
which will forward all requests to the configured address.

When VPN is enabled, dodo will run tailscale sidecar in the proxy pod.

Change-Id: I12592ae77d2e88e0582c8fe1e0f82e5fd24e02cb
diff --git a/core/installer/dodo_app_test.go b/core/installer/dodo_app_test.go
index a733c11..73f7025 100644
--- a/core/installer/dodo_app_test.go
+++ b/core/installer/dodo_app_test.go
@@ -149,59 +149,66 @@
 
 const canvas = `
 {
-    "service": [
+  "service": [
+    {
+      "type": "nextjs:deno-2.0.0",
+      "name": "app",
+      "source": {
+        "repository": "ssh://d.p.v1.dodo.cloud:62533/myblog",
+        "branch": "master",
+        "rootDir": "/"
+      },
+      "ports": [
         {
-            "type": "nextjs:deno-2.0.0",
-            "name": "app",
-            "source": {
-                "repository": "ssh://d.p.v1.dodo.cloud:62533/myblog",
-                "branch": "master",
-                "rootDir": "/"
-            },
-            "ports": [
-                {
-                    "name": "web",
-                    "value": 3000,
-                    "protocol": "TCP"
-                }
-            ],
-            "env": [
-                {
-                    "name": "DODO_POSTGRESQL_DB_CONNECTION_URL"
-                }
-            ],
-            "ingress": [{
-                "network": "Private",
-                "subdomain": "foo",
-                "port": {
-                    "name": "web"
-                },
-                "auth": {
-                    "enabled": false
-                }
-            }, {
-                "network": "Public",
-                "subdomain": "foo",
-                "port": {
-                    "name": "web"
-                },
-                "auth": {
-                    "enabled": false
-                }
-            }],
-            "expose": [],
-            "dev": { "enabled": true, "username": "gio" }
+          "name": "web",
+          "value": 3000,
+          "protocol": "TCP"
         }
-    ],
-    "volume": [],
-    "postgresql": [
+      ],
+      "env": [
         {
-            "name": "db",
-            "size": "1Gi",
-            "expose": []
+          "name": "DODO_POSTGRESQL_DB_CONNECTION_URL"
         }
-    ],
-    "mongodb": []
+      ],
+      "ingress": [
+        {
+          "network": "Private",
+          "subdomain": "foo",
+          "port": {
+            "name": "web"
+          },
+          "auth": {
+            "enabled": false
+          }
+        },
+        {
+          "network": "Public",
+          "subdomain": "foo",
+          "port": {
+            "name": "web"
+          },
+          "auth": {
+            "enabled": false
+          }
+        }
+      ],
+      "expose": [],
+      "dev": {
+        "enabled": true,
+        "mode": "VM",
+        "username": "gio"
+      }
+    }
+  ],
+  "volume": [],
+  "postgresql": [
+    {
+      "name": "db",
+      "size": "1Gi",
+      "expose": []
+    }
+  ],
+  "mongodb": []
 }
 `
 
@@ -481,6 +488,7 @@
       }],
       "dev": {
         "enabled": true,
+        "mode": "VM",
         "username": "gio",
         "codeServer": {
           "network": "Private",
@@ -535,78 +543,67 @@
 
 const foo = `
 {
-  "service": [
-    {
-      "type": "deno:2.2.0",
-      "name": "qwe",
-      "source": {
-        "repository": "git@github.com:giolekva/dodo-blog.git"
-      },
-      "ports": [
-        {
-          "name": "web",
-          "value": 8080,
-          "protocol": "TCP"
-        }
-      ],
-      "env": [
-        {
-          "name": "DODO_POSTGRESQL_DB_URL"
-        },
-        {
-          "name": "DODO_PORT_WEB"
-        }
-      ],
-      "ingress": [
-        {
-          "network": "Private",
-          "subdomain": "blog",
-          "port": {
-            "name": "web"
-          },
-          "auth": {
-            "enabled": false
-          }
-        }
-      ],
-      "expose": [
-        {
-          "network": "Private",
-          "subdomain": "blog",
-          "port": {
-            "name": "web"
-          }
-        }
-      ],
-      "preBuildCommands": [],
-      "dev": {
-        "enabled": true,
-        "username": "gio",
-        "codeServer": {
-          "network": "Private",
-          "subdomain": "code"
-        },
-        "ssh": {
-          "network": "Public",
-          "subdomain": "code"
-        }
-      }
-    }
-  ],
-  "volume": [],
-  "postgresql": [
-    {
-      "name": "db",
-      "size": "1Gi",
-      "expose": [
-        {
-          "network": "Private",
-          "subdomain": "pg"
-        }
-      ]
-    }
-  ],
-  "mongodb": []
+	"service": [
+		{
+			"type": "deno:2.2.0",
+			"name": "qwe",
+			"source": {
+				"repository": "git@github.com:giolekva/dodo-blog.git"
+			},
+			"ports": [
+				{
+					"name": "web",
+					"value": 8081,
+					"protocol": "TCP"
+				}
+			],
+			"env": [
+				{
+					"name": "DODO_POSTGRESQL_DB_URL"
+				},
+				{
+					"name": "DODO_PORT_WEB"
+				}
+			],
+			"ingress": [
+				{
+					"network": "Private",
+					"subdomain": "blog",
+					"port": {
+						"name": "web"
+					},
+					"auth": {
+						"enabled": false
+					}
+				}
+			],
+			"expose": [
+				{
+					"network": "Private",
+					"subdomain": "blog",
+					"port": {
+						"name": "web"
+					}
+				}
+			],
+			"preBuildCommands": [],
+			"dev": {
+				"enabled": true,
+				"mode": "PROXY",
+				"vpn": { "enabled": true, "username": "gio" },
+				"address": "65.108.39.172",
+				"ports": [
+					{
+						"src": 8081,
+						"dst": 80
+					}
+				]
+			}
+		}
+	],
+	"volume": [],
+	"postgresql": [],
+	"mongodb": []
 }
 `
 
@@ -636,11 +633,7 @@
 	if err != nil {
 		t.Fatal(err)
 	}
-	access, err := json.Marshal(r.Access)
-	if err != nil {
-		t.Fatal(err)
-	}
-	t.Log(string(access))
+	t.Log(string(r.Raw))
 }
 
 const sketch = `