From 5c98ce26778d07ea5194bb186b032955599e48f8 Mon Sep 17 00:00:00 2001 From: Gyanendra Mishra Date: Wed, 13 Mar 2024 21:17:19 +0000 Subject: [PATCH] feat: port guessing based on port number for docker transpiler (#2281) - [x] needs test - [ ] maybe visit http port scanning?? --- .../docker_compose_transpiler.go | 16 +++++++++-- .../docker_compose_transpiler_test.go | 28 +++++++++---------- docs/docs/guides/running-docker-compose.md | 2 +- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/core/server/api_container/server/docker_compose_transpiler/docker_compose_transpiler.go b/core/server/api_container/server/docker_compose_transpiler/docker_compose_transpiler.go index f1bf0a98a5..685aa043dd 100644 --- a/core/server/api_container/server/docker_compose_transpiler/docker_compose_transpiler.go +++ b/core/server/api_container/server/docker_compose_transpiler/docker_compose_transpiler.go @@ -3,6 +3,7 @@ package docker_compose_transpiler import ( "errors" "fmt" + "golang.org/x/exp/slices" "os" "path" "sort" @@ -59,8 +60,12 @@ const ( unixHomePathSymbol = "~" upstreamRelativePathSymbol = ".." + + httpProtocol = "http" ) +var possibleHttpPorts = []uint32{8080, 8000, 80, 443} + type ComposeService types.ServiceConfig type StarlarkServiceConfig *kurtosis_type_constructor.KurtosisValueTypeDefault @@ -379,13 +384,18 @@ func getStarlarkPortSpecs(serviceName string, composePorts []types.ServicePortCo return nil, stacktrace.NewError("Port #%d has unsupported protocol '%v'", portIdx, dockerProto) } + var applicationProtocol string + if slices.Contains(possibleHttpPorts, dockerPort.Target) { + applicationProtocol = httpProtocol + } + portSpec, interpretationErr := port_spec_starlark.CreatePortSpecUsingGoValues( serviceName, uint16(dockerPort.Target), kurtosisProto, - nil, // Application protocol (which Compose doesn't have) - "", // Wait timeout (which Compose doesn't have a way to override) - nil, // No way to change the URL for the port + &applicationProtocol, // Application protocol (which Compose doesn't have) + "", // Wait timeout (which Compose doesn't have a way to override) + nil, // No way to change the URL for the port ) if interpretationErr != nil { return nil, stacktrace.Propagate(interpretationErr, "An error occurred creating a %s object from port #%d", port_spec_starlark.PortSpecTypeName, portIdx) diff --git a/core/server/api_container/server/docker_compose_transpiler/docker_compose_transpiler_test.go b/core/server/api_container/server/docker_compose_transpiler/docker_compose_transpiler_test.go index 1dc18964ed..d8c106583a 100644 --- a/core/server/api_container/server/docker_compose_transpiler/docker_compose_transpiler_test.go +++ b/core/server/api_container/server/docker_compose_transpiler/docker_compose_transpiler_test.go @@ -18,7 +18,7 @@ services: `) expectedResult := `def run(plan): - plan.add_service(name = "web", config = ServiceConfig(image="app/server", ports={"port0": PortSpec(number=80, transport_protocol="TCP")}, env_vars={})) + plan.add_service(name = "web", config = ServiceConfig(image="app/server", ports={"port0": PortSpec(number=80, transport_protocol="TCP", application_protocol="http", url="http://web:80")}, env_vars={})) ` result, err := convertComposeToStarlarkScript(composeBytes, map[string]string{}) @@ -35,7 +35,7 @@ services: - 80:80 `) expectedResult := fmt.Sprintf(`def run(plan): - plan.add_service(name = "web", config = ServiceConfig(image=ImageBuildSpec(image_name="web%s", build_context_dir="app/server"), ports={"port0": PortSpec(number=80, transport_protocol="TCP")}, env_vars={})) + plan.add_service(name = "web", config = ServiceConfig(image=ImageBuildSpec(image_name="web%s", build_context_dir="app/server"), ports={"port0": PortSpec(number=80, transport_protocol="TCP", application_protocol="http", url="http://web:80")}, env_vars={})) `, builtImageSuffix) result, err := convertComposeToStarlarkScript(composeBytes, map[string]string{}) @@ -54,7 +54,7 @@ services: - 80:80 `) expectedResult := fmt.Sprintf(`def run(plan): - plan.add_service(name = "web", config = ServiceConfig(image=ImageBuildSpec(image_name="web%s", build_context_dir="app", target_stage="builder"), ports={"port0": PortSpec(number=80, transport_protocol="TCP")}, env_vars={})) + plan.add_service(name = "web", config = ServiceConfig(image=ImageBuildSpec(image_name="web%s", build_context_dir="app", target_stage="builder"), ports={"port0": PortSpec(number=80, transport_protocol="TCP", application_protocol="http", url="http://web:80")}, env_vars={})) `, builtImageSuffix) result, err := convertComposeToStarlarkScript(composeBytes, map[string]string{}) @@ -76,7 +76,7 @@ services: `) expectedResult := fmt.Sprintf(`def run(plan): plan.upload_files(src = "./data", name = "web--volume0") - plan.add_service(name = "web", config = ServiceConfig(image=ImageBuildSpec(image_name="web%s", build_context_dir="app", target_stage="builder"), ports={"port0": PortSpec(number=80, transport_protocol="TCP")}, files={"/data": "web--volume0"}, env_vars={})) + plan.add_service(name = "web", config = ServiceConfig(image=ImageBuildSpec(image_name="web%s", build_context_dir="app", target_stage="builder"), ports={"port0": PortSpec(number=80, transport_protocol="TCP", application_protocol="http", url="http://web:80")}, files={"/data": "web--volume0"}, env_vars={})) `, builtImageSuffix) result, err := convertComposeToStarlarkScript(composeBytes, map[string]string{}) @@ -97,7 +97,7 @@ services: - /project/node_modules `) expectedResult := fmt.Sprintf(`def run(plan): - plan.add_service(name = "web", config = ServiceConfig(image=ImageBuildSpec(image_name="web%s", build_context_dir="app", target_stage="builder"), ports={"port0": PortSpec(number=80, transport_protocol="TCP")}, files={"/project/node_modules": Directory(persistent_key="web--volume0")}, env_vars={})) + plan.add_service(name = "web", config = ServiceConfig(image=ImageBuildSpec(image_name="web%s", build_context_dir="app", target_stage="builder"), ports={"port0": PortSpec(number=80, transport_protocol="TCP", application_protocol="http", url="http://web:80")}, files={"/project/node_modules": Directory(persistent_key="web--volume0")}, env_vars={})) `, builtImageSuffix) result, err := convertComposeToStarlarkScript(composeBytes, map[string]string{}) @@ -118,7 +118,7 @@ services: - /project/node_modules:/node_modules `) expectedResult := fmt.Sprintf(`def run(plan): - plan.add_service(name = "web", config = ServiceConfig(image=ImageBuildSpec(image_name="web%s", build_context_dir="app", target_stage="builder"), ports={"port0": PortSpec(number=80, transport_protocol="TCP")}, files={"/node_modules": Directory(persistent_key="web--volume0")}, env_vars={})) + plan.add_service(name = "web", config = ServiceConfig(image=ImageBuildSpec(image_name="web%s", build_context_dir="app", target_stage="builder"), ports={"port0": PortSpec(number=80, transport_protocol="TCP", application_protocol="http", url="http://web:80")}, files={"/node_modules": Directory(persistent_key="web--volume0")}, env_vars={})) `, builtImageSuffix) result, err := convertComposeToStarlarkScript(composeBytes, map[string]string{}) @@ -147,8 +147,8 @@ services: - /project/node_modules:/node_modules `) expectedResult := fmt.Sprintf(`def run(plan): - plan.add_service(name = "web2", config = ServiceConfig(image=ImageBuildSpec(image_name="web2%s", build_context_dir="app", target_stage="builder"), ports={"port0": PortSpec(number=80, transport_protocol="TCP")}, files={"/node_modules": Directory(persistent_key="web2--volume0")}, env_vars={})) - plan.add_service(name = "web3", config = ServiceConfig(image=ImageBuildSpec(image_name="web3%s", build_context_dir="app", target_stage="builder"), ports={"port0": PortSpec(number=80, transport_protocol="TCP")}, files={"/node_modules": Directory(persistent_key="web3--volume0")}, env_vars={})) + plan.add_service(name = "web2", config = ServiceConfig(image=ImageBuildSpec(image_name="web2%s", build_context_dir="app", target_stage="builder"), ports={"port0": PortSpec(number=80, transport_protocol="TCP", application_protocol="http", url="http://web2:80")}, files={"/node_modules": Directory(persistent_key="web2--volume0")}, env_vars={})) + plan.add_service(name = "web3", config = ServiceConfig(image=ImageBuildSpec(image_name="web3%s", build_context_dir="app", target_stage="builder"), ports={"port0": PortSpec(number=80, transport_protocol="TCP", application_protocol="http", url="http://web3:80")}, files={"/node_modules": Directory(persistent_key="web3--volume0")}, env_vars={})) `, builtImageSuffix, builtImageSuffix) result, err := convertComposeToStarlarkScript(composeBytes, map[string]string{}) @@ -179,7 +179,7 @@ services: `) expectedResult := fmt.Sprintf(`def run(plan): plan.upload_files(src = "./data", name = "web--volume0") - plan.add_service(name = "web", config = ServiceConfig(image=ImageBuildSpec(image_name="web%s", build_context_dir="app", target_stage="builder"), ports={"port0": PortSpec(number=80, transport_protocol="TCP")}, files={"/data": "web--volume0", "/node_modules": Directory(persistent_key="web--volume1")}, entrypoint=["/bin/echo", "-c", "echo \"Hello\""], cmd=["echo", "Hello,", "World!"], env_vars={"NODE_ENV": "development"})) + plan.add_service(name = "web", config = ServiceConfig(image=ImageBuildSpec(image_name="web%s", build_context_dir="app", target_stage="builder"), ports={"port0": PortSpec(number=80, transport_protocol="TCP", application_protocol="http", url="http://web:80")}, files={"/data": "web--volume0", "/node_modules": Directory(persistent_key="web--volume1")}, entrypoint=["/bin/echo", "-c", "echo \"Hello\""], cmd=["echo", "Hello,", "World!"], env_vars={"NODE_ENV": "development"})) `, builtImageSuffix) result, err := convertComposeToStarlarkScript(composeBytes, map[string]string{}) @@ -214,7 +214,7 @@ services: - '80:80' `) expectedResult := fmt.Sprintf(`def run(plan): - plan.add_service(name = "nginx", config = ServiceConfig(image=ImageBuildSpec(image_name="nginx%s", build_context_dir="./nginx"), ports={"port0": PortSpec(number=80, transport_protocol="TCP")}, env_vars={})) + plan.add_service(name = "nginx", config = ServiceConfig(image=ImageBuildSpec(image_name="nginx%s", build_context_dir="./nginx"), ports={"port0": PortSpec(number=80, transport_protocol="TCP", application_protocol="http", url="http://nginx:80")}, env_vars={})) plan.add_service(name = "redis", config = ServiceConfig(image="redislabs/redismod", ports={"port0": PortSpec(number=6379, transport_protocol="TCP")}, env_vars={})) plan.add_service(name = "web1", config = ServiceConfig(image=ImageBuildSpec(image_name="web1%s", build_context_dir="./web"), ports={"port0": PortSpec(number=5000, transport_protocol="TCP")}, env_vars={})) plan.add_service(name = "web2", config = ServiceConfig(image=ImageBuildSpec(image_name="web2%s", build_context_dir="./web"), ports={"port0": PortSpec(number=5000, transport_protocol="TCP")}, env_vars={})) @@ -331,7 +331,7 @@ services: plan.add_service(name = "redis", config = ServiceConfig(image="redislabs/redismod", ports={"port0": PortSpec(number=6379, transport_protocol="TCP")}, env_vars={})) plan.add_service(name = "web1", config = ServiceConfig(image=ImageBuildSpec(image_name="web1%s", build_context_dir="./web"), ports={"port0": PortSpec(number=5000, transport_protocol="TCP")}, env_vars={})) plan.add_service(name = "web2", config = ServiceConfig(image=ImageBuildSpec(image_name="web2%s", build_context_dir="./web"), ports={"port0": PortSpec(number=5000, transport_protocol="TCP")}, env_vars={})) - plan.add_service(name = "nginx", config = ServiceConfig(image=ImageBuildSpec(image_name="nginx%s", build_context_dir="./nginx"), ports={"port0": PortSpec(number=80, transport_protocol="TCP")}, env_vars={})) + plan.add_service(name = "nginx", config = ServiceConfig(image=ImageBuildSpec(image_name="nginx%s", build_context_dir="./nginx"), ports={"port0": PortSpec(number=80, transport_protocol="TCP", application_protocol="http", url="http://nginx:80")}, env_vars={})) `, builtImageSuffix, builtImageSuffix, builtImageSuffix) result, err := convertComposeToStarlarkScript(composeBytes, map[string]string{}) @@ -509,7 +509,7 @@ services: restart: "no" `) expectedResult := fmt.Sprintf(`def run(plan): - plan.add_service(name = "api", config = ServiceConfig(image=ImageBuildSpec(image_name="api%v", build_context_dir=".", target_stage="builder"), ports={"port0": PortSpec(number=8000, transport_protocol="TCP")}, env_vars={"PORT": "8000"})) + plan.add_service(name = "api", config = ServiceConfig(image=ImageBuildSpec(image_name="api%v", build_context_dir=".", target_stage="builder"), ports={"port0": PortSpec(number=8000, transport_protocol="TCP", application_protocol="http", url="http://api:8000")}, env_vars={"PORT": "8000"})) `, builtImageSuffix) result, err := convertComposeToStarlarkScript(composeBytes, map[string]string{}) @@ -542,7 +542,7 @@ services: expectedResult := fmt.Sprintf(`def run(plan): plan.add_service(name = "redis", config = ServiceConfig(image="redislabs/redismod", ports={"port0": PortSpec(number=6379, transport_protocol="TCP")}, env_vars={})) plan.upload_files(src = "./code", name = "web--volume0") - plan.add_service(name = "web", config = ServiceConfig(image=ImageBuildSpec(image_name="web%v", build_context_dir=".", target_stage="builder"), ports={"port0": PortSpec(number=8000, transport_protocol="TCP")}, files={"/code": "web--volume0"}, env_vars={})) + plan.add_service(name = "web", config = ServiceConfig(image=ImageBuildSpec(image_name="web%v", build_context_dir=".", target_stage="builder"), ports={"port0": PortSpec(number=8000, transport_protocol="TCP", application_protocol="http", url="http://web:8000")}, files={"/code": "web--volume0"}, env_vars={})) `, builtImageSuffix) result, err := convertComposeToStarlarkScript(composeBytes, map[string]string{}) @@ -601,7 +601,7 @@ networks: `) expectedResult := `def run(plan): plan.add_service(name = "db", config = ServiceConfig(image="mariadb:10.5", files={"/var/lib/mysql": Directory(persistent_key="db--volume0")}, cmd=["--transaction-isolation=READ-COMMITTED", "--binlog-format=ROW"], env_vars={"MYSQL_DATABASE": "nextcloud", "MYSQL_PASSWORD": "nextcloud", "MYSQL_ROOT_PASSWORD": "nextcloud", "MYSQL_USER": "nextcloud"})) - plan.add_service(name = "nc", config = ServiceConfig(image="nextcloud:apache", ports={"port0": PortSpec(number=80, transport_protocol="TCP")}, files={"/var/www/html": Directory(persistent_key="nc--volume0")}, env_vars={"MYSQL_DATABASE": "nextcloud", "MYSQL_HOST": "db", "MYSQL_PASSWORD": "nextcloud", "MYSQL_USER": "nextcloud", "REDIS_HOST": "redis"})) + plan.add_service(name = "nc", config = ServiceConfig(image="nextcloud:apache", ports={"port0": PortSpec(number=80, transport_protocol="TCP", application_protocol="http", url="http://nc:80")}, files={"/var/www/html": Directory(persistent_key="nc--volume0")}, env_vars={"MYSQL_DATABASE": "nextcloud", "MYSQL_HOST": "db", "MYSQL_PASSWORD": "nextcloud", "MYSQL_USER": "nextcloud", "REDIS_HOST": "redis"})) plan.add_service(name = "redis", config = ServiceConfig(image="redis:alpine", env_vars={})) ` diff --git a/docs/docs/guides/running-docker-compose.md b/docs/docs/guides/running-docker-compose.md index a0f5402c13..b8ba341866 100644 --- a/docs/docs/guides/running-docker-compose.md +++ b/docs/docs/guides/running-docker-compose.md @@ -90,7 +90,7 @@ Container images used in this run: > add_service name="db" config=ServiceConfig(image="mariadb:10.5", files={"/var/lib/mysql": Directory(persistent_key="db--volume0")}, cmd=["--transaction-isolation=READ-COMMITTED", "--binlog-format=ROW"], env_vars={"MYSQL_DATABASE": "nextcloud", "MYSQL_PASSWORD": "nextcloud", "MYSQL_ROOT_PASSWORD": "nextcloud", "MYSQL_USER": "nextcloud"}) Service 'db' added with service UUID '7010d01344e34a7c9f061d4fa43e5e0d' -> add_service name="nc" config=ServiceConfig(image="nextcloud:apache", ports={"port0": PortSpec(number=80, transport_protocol="TCP")}, files={"/var/www/html": Directory(persistent_key="nc--volume0")}, env_vars={"MYSQL_DATABASE": "nextcloud", "MYSQL_HOST": "db", "MYSQL_PASSWORD": "nextcloud", "MYSQL_USER": "nextcloud", "REDIS_HOST": "redis"}) +> add_service name="nc" config=ServiceConfig(image="nextcloud:apache", ports={"port0": PortSpec(number=80, transport_protocol="TCP", application_protocol="http", url="http://web:80")}, files={"/var/www/html": Directory(persistent_key="nc--volume0")}, env_vars={"MYSQL_DATABASE": "nextcloud", "MYSQL_HOST": "db", "MYSQL_PASSWORD": "nextcloud", "MYSQL_USER": "nextcloud", "REDIS_HOST": "redis"}) Service 'nc' added with service UUID 'c30843ea60b8459c8841565a11be5dde' > add_service name="redis" config=ServiceConfig(image="redis:alpine", env_vars={})