Skip to content

Commit

Permalink
feat: port guessing based on port number for docker transpiler (#2281)
Browse files Browse the repository at this point in the history
- [x] needs test
- [ ] maybe visit http port scanning??
  • Loading branch information
h4ck3rk3y authored Mar 13, 2024
1 parent 7fa27ed commit 5c98ce2
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package docker_compose_transpiler
import (
"errors"
"fmt"
"golang.org/x/exp/slices"
"os"
"path"
"sort"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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{})
Expand All @@ -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{})
Expand All @@ -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{})
Expand All @@ -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{})
Expand All @@ -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{})
Expand All @@ -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{})
Expand Down Expand Up @@ -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{})
Expand Down Expand Up @@ -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{})
Expand Down Expand Up @@ -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={}))
Expand Down Expand Up @@ -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{})
Expand Down Expand Up @@ -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{})
Expand Down Expand Up @@ -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{})
Expand Down Expand Up @@ -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={}))
`

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/guides/running-docker-compose.md
Original file line number Diff line number Diff line change
Expand Up @@ -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={})
Expand Down

0 comments on commit 5c98ce2

Please sign in to comment.