Skip to content

Commit

Permalink
Host port mapping recipes (#521)
Browse files Browse the repository at this point in the history
* Implement --map-ports-to-host feature
  • Loading branch information
dboreham authored Sep 4, 2023
1 parent e89f7c9 commit f48f497
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 16 deletions.
2 changes: 1 addition & 1 deletion app/data/compose/docker-compose-fixturenet-laconicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ services:
- "6060"
- "26657"
- "26656"
- "9473:9473"
- "9473"
- "8545"
- "8546"
- "9090"
Expand Down
2 changes: 1 addition & 1 deletion app/data/compose/docker-compose-mainnet-laconicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ services:
- "6060"
- "26657"
- "26656"
- "9473:9473"
- "9473"
- "8545"
- "8546"
- "9090"
Expand Down
12 changes: 10 additions & 2 deletions app/data/stacks/mainnet-eth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ After deleting the volumes, any subsequent re-start will begin chain sync from c

## Ports
It is usually necessary to expose certain container ports on one or more the host's addresses to allow incoming connections.
Any ports defined in the Docker compose file are exposed by default with random port assignments, but the values can be
Any ports defined in the Docker compose file are exposed by default with random port assignments, bound to "any" interface (IP address 0.0.0.0), but the port mappings can be
customized by editing the "spec" file generated by `laconic-so deploy init`.

In this example, ports `8545` and `5052` have been assigned to a specific addresses/port combination on the host, while
Expand All @@ -92,7 +92,15 @@ volumes:
mainnet_eth_geth_1_data: ./data/mainnet_eth_geth_1_data
mainnet_eth_lighthouse_1_data: ./data/mainnet_eth_lighthouse_1_data
```

In addition, a stack-wide port mapping "recipe" can be applied at the time the
`laconic-so deploy init` command is run, by supplying the desired recipe with the `--map-ports-to-host` option. The following recipes are supported:
| Recipe | Host Port Mapping |
|--------|-------------------|
| any-variable-random | Bind to 0.0.0.0 using a random port assigned at start time (default) |
| localhost-same | Bind to 127.0.0.1 using the same port number as exposed by the containers |
| any-same | Bind to 0.0.0.0 using the same port number as exposed by the containers |
| localhost-fixed-random | Bind to 127.0.0.1 using a random port number selected at the time the command is run (not checked for already in use)|
| any-fixed-random | Bind to 0.0.0.0 using a random port number selected at the time the command is run (not checked for already in use) |
## Data volumes
Container data volumes are bind-mounted to specified paths in the host filesystem.
The default setup (generated by `laconic-so deploy init`) places the volumes in the `./data` subdirectory of the deployment directory:
Expand Down
4 changes: 0 additions & 4 deletions app/data/stacks/mainnet-laconic/deploy/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@
chain_id: my-chain-id
"""

init_help_text = """Add helpful text here on setting config variables.
"""


class SetupPhase(Enum):
INITIALIZE = 1
Expand Down Expand Up @@ -275,7 +272,6 @@ def create(command_context: DeployCommandContext, extra_args):


def init(command_context: DeployCommandContext):
print(init_help_text)
yaml = get_yaml()
return yaml.load(default_spec_file_content)

Expand Down
4 changes: 0 additions & 4 deletions app/data/stacks/test/deploy/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@
config_variable: test-value
"""

init_help_text = """Add helpful text here on setting config variables.
"""


# Output a known string to a know file in the bind mounted directory ./container-output-dir
# for test purposes -- test checks that the file was written.
Expand All @@ -40,7 +37,6 @@ def setup(command_context: DeployCommandContext, parameters, extra_args):


def init(command_context: DeployCommandContext):
print(init_help_text)
yaml = get_yaml()
return yaml.load(default_spec_file_content)

Expand Down
46 changes: 42 additions & 4 deletions app/deployment_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from importlib import util
import os
from pathlib import Path
import random
from shutil import copyfile, copytree
import sys
from app.util import get_stack_file_path, get_parsed_deployment_spec, get_parsed_stack_config, global_options, get_yaml
Expand Down Expand Up @@ -166,10 +167,48 @@ def _find_extra_config_dirs(parsed_pod_file, pod):
return config_dirs


def _get_mapped_ports(stack: str, map_recipe: str):
port_map_recipes = ["any-variable-random", "localhost-same", "any-same", "localhost-fixed-random", "any-fixed-random"]
ports = _get_ports(stack)
if ports:
# Implement any requested mapping recipe
if map_recipe:
if map_recipe in port_map_recipes:
for service in ports.keys():
ports_array = ports[service]
for x in range(0, len(ports_array)):
orig_port = ports_array[x]
random_port = random.randint(20000,50000) # Beware: we're relying on luck to not collide
if map_recipe == "any-variable-random":
# This is the default so take no action
pass
elif map_recipe == "localhost-same":
# Replace instances of "- XX" with "- 127.0.0.1:XX"
ports_array[x] = f"127.0.0.1:{orig_port}:{orig_port}"
elif map_recipe == "any-same":
# Replace instances of "- XX" with "- 0.0.0.0:XX"
ports_array[x] = f"0.0.0.0:{orig_port}:{orig_port}"
elif map_recipe == "localhost-fixed-random":
# Replace instances of "- XX" with "- 127.0.0.1:<rnd>:XX"
ports_array[x] = f"127.0.0.1:{random_port}:{orig_port}"
elif map_recipe == "any-fixed-random":
# Replace instances of "- XX" with "- 0.0.0.0:<rnd>:XX"
ports_array[x] = f"0.0.0.0:{random_port}:{orig_port}"
else:
print("Error: bad map_recipe")
else:
print(f"Error: --map-ports-to-host must specify one of: {port_map_recipes}")
sys.exit(1)
return ports



@click.command()
@click.option("--output", required=True, help="Write yaml spec file here")
@click.option("--map-ports-to-host", required=False,
help="Map ports to the host as one of: any-variable-random (default), localhost-same, any-same, localhost-fixed-random, any-fixed-random")
@click.pass_context
def init(ctx, output):
def init(ctx, output, map_ports_to_host):
yaml = get_yaml()
stack = global_options(ctx).stack
verbose = global_options(ctx).verbose
Expand All @@ -180,9 +219,8 @@ def init(ctx, output):
if verbose:
print(f"Creating spec file for stack: {stack}")

ports = _get_ports(stack)
if ports:
spec_file_content["ports"] = ports
ports = _get_mapped_ports(stack, map_ports_to_host)
spec_file_content["ports"] = ports

named_volumes = _get_named_volumes(stack)
if named_volumes:
Expand Down

0 comments on commit f48f497

Please sign in to comment.