Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

86 - Additional additions for Edge CLI support #87

Merged
merged 19 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions Minimal/app_config.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
env_name: edge-minimal-example
edm_deps:
- click
- pip
image_name: edge-minimal-example
framework: generic
app_id: null
app_version: 1.2.0
python_version: 3.8
repository: quay.io
organisation: enthought
env_deps:
edm:
- click
- filetype
- oauthlib
- pip
- python_dateutil
- pyyaml
- requests
- setuptools
pip:
- questionary
- src_edge/src
app_deps:
- flask
- setuptools
- gunicorn
- enthought_edge
cmd_deps:
- docker
framework: generic
app_id: null
exclude:
- bootstrap.py
2 changes: 1 addition & 1 deletion Minimal/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@


ENV_NAME = "edge-minimal-example"
EDM_DEPS = ["click", "pip", "setuptools"]
EDM_DEPS = ["click", "pip", "pyyaml", "setuptools"]


def bootstrap(ci_mode):
Expand Down
87 changes: 66 additions & 21 deletions Minimal/ci/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,42 @@
"""
This is the "ci" module for the minimal example.
"""

import click
import os.path as op
import subprocess
import json
import yaml

SRC_ROOT = op.abspath(op.join(op.dirname(__file__), ".."))

# Docker image will be tagged "IMAGE:VERSION"
IMAGE = "quay.io/enthought/edge-example-minimal"
VERSION = "1.2.0"

# These will go into the built Docker image. You may wish to modify this
# minimal example to pin the dependencies, or use a bundle file to define them.
APP_DEPENDENCIES = ["flask", "setuptools", "gunicorn", "enthought_edge"]

# This will be used when running locally ("run" command).
# We just use the last component of the full image URL.
CONTAINER_NAME = IMAGE.split("/")[-1]
def _bundle_image(config: dict) -> str:
"""Assemble a bundle image name from the configuration settings."""
return "/".join([config["repository"],
config["organisation"],
config["image_name"]])


@click.group()
def cli():
@click.pass_context
def cli(ctx):
"""Group for Click commands"""
pass
config = _load_config_settings()
ctx.obj = config


@cli.command()
@click.option("--rebuild-zbundle", default=False, is_flag=True)
def build(rebuild_zbundle):
@click.option("--verbose", default=False, is_flag=True)
@click.pass_obj
def build(config, rebuild_zbundle, verbose):
"""Build the Docker image"""

# Configuration details
bundle_image = _bundle_image(config)
version = config["app_version"]
app_deps = config["app_deps"]

# First, we build a "zbundle" which contains all the eggs needed to
# build the environment within the Docker image.
fname = "app_environment.zbundle"
Expand All @@ -58,35 +62,57 @@ def build(rebuild_zbundle):
"2.0",
"-f",
fname,
] + APP_DEPENDENCIES
] + app_deps
if verbose:
click.echo(" ".join(cmd))
subprocess.run(cmd, check=True, cwd=SRC_ROOT)

# Finally, we run Docker. The Dockerfile will copy the zbundle into
# a temp folder and install it.
cmd = ["docker", "build", "-t", f"{IMAGE}:{VERSION}", "."]
cmd = ["docker", "build", "-t", f"{bundle_image}:{version}", "."]
if verbose:
click.echo(" ".join(cmd))
subprocess.run(cmd, check=True, cwd=SRC_ROOT)


@cli.command()
def run():
@click.option("--verbose", default=False, is_flag=True)
@click.pass_obj
def run(config, verbose):
"""Run the Docker image for testing"""

# Configuration details
bundle_image = _bundle_image(config)
container_name = config["image_name"]
version = config["app_version"]

# Get values from the dev settings file (API tokens for testing, etc.)
envs = _load_dev_settings()

cmd = ["docker", "run", "--rm", "-p", "9000:9000", "--name", CONTAINER_NAME]
cmd = ["docker", "run", "--rm", "-p", "9000:9000", "--name", container_name]
for key, value in envs.items():
cmd += ["--env", f"{key}={value}"]
cmd += ["--env", "HOST_ADDRESS=0.0.0.0"]
cmd += [f"{IMAGE}:{VERSION}"]
cmd += [f"{bundle_image}:{version}"]

if verbose:
click.echo(" ".join(cmd))
subprocess.run(cmd, check=True, cwd=SRC_ROOT)


@cli.command()
def publish():
@click.option("--verbose", default=False, is_flag=True)
@click.pass_obj
def publish(config, verbose):
"""Publish the Docker image for use with Edge"""
cmd = ["docker", "push", f"{IMAGE}:{VERSION}"]

# Configuration details
bundle_image = _bundle_image(config)
version = config["app_version"]

cmd = ["docker", "push", f"{bundle_image}:{version}"]
if verbose:
click.echo(" ".join(cmd))
subprocess.run(cmd, check=True)


Expand All @@ -104,5 +130,24 @@ def _load_dev_settings():
return {k: v for k, v in data.items() if k.startswith("EDGE_")}


def _load_config_settings():
"""Load the application configuration settings.

Returns
-------
dict
The configuration settings.
"""
data = {}
fpath = op.join(SRC_ROOT, "app_config.yaml")
if op.exists(fpath):
with open(fpath, "r") as f:
data = yaml.safe_load(f)

if not data:
raise ValueError("Could not load app_config.yaml")
return data


if __name__ == "__main__":
cli()
37 changes: 32 additions & 5 deletions Panel/app_config.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,36 @@
env_name: edge-panel-example
edm_deps:
- click
image_name: edge-panel-example
framework: panel
app_id: null
app_version: 1.3.0
python_version: 3.8
repository: quay.io
organisation: enthought
env_deps:
edm:
- click
- filetype
- oauthlib
- pip
- python_dateutil
- pyyaml
- requests
- setuptools
pip:
- questionary
- src_edge/src
app_deps:
- enthought_edge>=2.16.0
- appdirs
- packaging
- pip
- pyparsing
- setuptools
- six
- panel
- numpy
- pandas
- matplotlib
cmd_deps:
- docker
framework: panel
app_id: null
exclude:
- bootstrap.py
103 changes: 67 additions & 36 deletions Panel/ci/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,52 +9,42 @@
"""
This is the "ci" module for the Panel example.
"""

import click
import os.path as op
import subprocess
import sys
import os
import json
import yaml

SRC_ROOT = op.abspath(op.join(op.dirname(__file__), ".."))

# Docker image will be tagged "IMAGE:VERSION"
IMAGE = "quay.io/enthought/edge-panel-example"
VERSION = "1.3.0"

# These will go into the built Docker image. You may wish to modify this
# minimal example to pin the dependencies, or use a bundle file to define them.
APP_DEPENDENCIES = [
"enthought_edge>=2.16.0",
"appdirs",
"packaging",
"pip",
"pyparsing",
"setuptools",
"six",
"panel",
"numpy",
"pandas",
"matplotlib",
]

# This will be used when running locally ("run" command).
# We just use the last component of the full image URL.
CONTAINER_NAME = IMAGE.split("/")[-1]

def _bundle_image(config: dict) -> str:
"""Assemble a bundle image name from the configuration settings."""
return "/".join([config["repository"],
config["organisation"],
config["image_name"]])


@click.group()
def cli():
@click.pass_context
def cli(ctx):
"""Group for Click commands"""
pass
config = _load_config_settings()
ctx.obj = config


@cli.command()
@click.option("--rebuild-zbundle", default=False, is_flag=True)
def build(rebuild_zbundle):
@click.option("--verbose", default=False, is_flag=True)
@click.pass_obj
def build(config, rebuild_zbundle, verbose):
"""Build the Docker image"""

# Configuration details
bundle_image = _bundle_image(config)
version = config["app_version"]
app_deps = config["app_deps"]

# First, we build a "zbundle" which contains all the eggs needed to
# build the environment within the Docker image.
fname = "app_environment.zbundle"
Expand All @@ -72,35 +62,57 @@ def build(rebuild_zbundle):
"2.0",
"-f",
fname,
] + APP_DEPENDENCIES
] + app_deps
if verbose:
click.echo(" ".join(cmd))
subprocess.run(cmd, check=True, cwd=SRC_ROOT)

# Finally, we run Docker. The Dockerfile will copy the zbundle into
# a temp folder and install it.
cmd = ["docker", "build", "-t", f"{IMAGE}:{VERSION}", "."]
cmd = ["docker", "build", "-t", f"{bundle_image}:{version}", "."]
if verbose:
click.echo(" ".join(cmd))
subprocess.run(cmd, check=True, cwd=SRC_ROOT)


@cli.command()
def run():
@click.option("--verbose", default=False, is_flag=True)
@click.pass_obj
def run(config, verbose):
"""Run the Docker image for testing"""

# Configuration details
bundle_image = _bundle_image(config)
container_name = config["image_name"]
version = config["app_version"]

# Get values from the dev settings file (API tokens for testing, etc.)
envs = _load_dev_settings()

cmd = ["docker", "run", "--rm", "-p", "9000:9000", "--name", CONTAINER_NAME]
cmd = ["docker", "run", "--rm", "-p", "9000:9000", "--name", container_name]
for key, value in envs.items():
cmd += ["--env", f"{key}={value}"]
cmd += ["--env", "HOST_ADDRESS=0.0.0.0"]
cmd += [f"{IMAGE}:{VERSION}"]
cmd += [f"{bundle_image}:{version}"]

if verbose:
click.echo(" ".join(cmd))
subprocess.run(cmd, check=True, cwd=SRC_ROOT)


@cli.command()
def publish():
@click.option("--verbose", default=False, is_flag=True)
@click.pass_obj
def publish(config, verbose):
"""Publish the Docker image for use with Edge"""
cmd = ["docker", "push", f"{IMAGE}:{VERSION}"]

# Configuration details
bundle_image = _bundle_image(config)
version = config["app_version"]

cmd = ["docker", "push", f"{bundle_image}:{version}"]
if verbose:
click.echo(" ".join(cmd))
subprocess.run(cmd, check=True)


Expand All @@ -118,5 +130,24 @@ def _load_dev_settings():
return {k: v for k, v in data.items() if k.startswith("EDGE_")}


def _load_config_settings():
"""Load the application configuration settings.

Returns
-------
dict
The configuration settings.
"""
data = {}
fpath = op.join(SRC_ROOT, "app_config.yaml")
if op.exists(fpath):
with open(fpath, "r") as f:
data = yaml.safe_load(f)

if not data:
raise ValueError("Could not load app_config.yaml")
return data


if __name__ == "__main__":
cli()
Loading
Loading