Propagate env file for webapp deployment #669

Merged
telackey merged 2 commits from dboreham/webapp-config into main 2023-11-29 04:14:02 +00:00
6 changed files with 33 additions and 15 deletions

View File

@ -14,6 +14,8 @@
# along with this program. If not, see <http:#www.gnu.org/licenses/>. # along with this program. If not, see <http:#www.gnu.org/licenses/>.
stack_file_name = "stack.yml" stack_file_name = "stack.yml"
spec_file_name = "spec.yml"
config_file_name = "config.env"
compose_deploy_type = "compose" compose_deploy_type = "compose"
k8s_kind_deploy_type = "k8s-kind" k8s_kind_deploy_type = "k8s-kind"
k8s_deploy_type = "k8s" k8s_deploy_type = "k8s"

View File

@ -25,7 +25,7 @@ from stack_orchestrator import constants
from stack_orchestrator.opts import opts from stack_orchestrator.opts import opts
from stack_orchestrator.util import (get_stack_file_path, get_parsed_deployment_spec, get_parsed_stack_config, from stack_orchestrator.util import (get_stack_file_path, get_parsed_deployment_spec, get_parsed_stack_config,
global_options, get_yaml, get_pod_list, get_pod_file_path, pod_has_scripts, global_options, get_yaml, get_pod_list, get_pod_file_path, pod_has_scripts,
get_pod_script_paths, get_plugin_code_paths, error_exit) get_pod_script_paths, get_plugin_code_paths, error_exit, env_var_map_from_file)
from stack_orchestrator.deploy.deploy_types import LaconicStackSetupCommand from stack_orchestrator.deploy.deploy_types import LaconicStackSetupCommand
from stack_orchestrator.deploy.deployer_factory import getDeployerConfigGenerator from stack_orchestrator.deploy.deployer_factory import getDeployerConfigGenerator
from stack_orchestrator.deploy.deployment_context import DeploymentContext from stack_orchestrator.deploy.deployment_context import DeploymentContext
@ -244,12 +244,13 @@ def _parse_config_variables(variable_values: str):
variable_name = variable_value_pair[0] variable_name = variable_value_pair[0]
variable_value = variable_value_pair[1] variable_value = variable_value_pair[1]
result_values[variable_name] = variable_value result_values[variable_name] = variable_value
result = {"config": result_values} result = result_values
return result return result
@click.command() @click.command()
@click.option("--config", help="Provide config variables for the deployment") @click.option("--config", help="Provide config variables for the deployment")
@click.option("--config-file", help="Provide config variables in a file for the deployment")
@click.option("--kube-config", help="Provide a config file for a k8s deployment") @click.option("--kube-config", help="Provide a config file for a k8s deployment")
@click.option("--image-registry", help="Provide a container image registry url for this k8s cluster") @click.option("--image-registry", help="Provide a container image registry url for this k8s cluster")
@click.option("--output", required=True, help="Write yaml spec file here") @click.option("--output", required=True, help="Write yaml spec file here")
@ -257,14 +258,15 @@ def _parse_config_variables(variable_values: str):
help="Map ports to the host as one of: any-variable-random (default), " help="Map ports to the host as one of: any-variable-random (default), "
"localhost-same, any-same, localhost-fixed-random, any-fixed-random") "localhost-same, any-same, localhost-fixed-random, any-fixed-random")
@click.pass_context @click.pass_context
def init(ctx, config, kube_config, image_registry, output, map_ports_to_host): def init(ctx, config, config_file, kube_config, image_registry, output, map_ports_to_host):
stack = global_options(ctx).stack stack = global_options(ctx).stack
deployer_type = ctx.obj.deployer.type deployer_type = ctx.obj.deployer.type
deploy_command_context = ctx.obj deploy_command_context = ctx.obj
return init_operation( return init_operation(
deploy_command_context, deploy_command_context,
stack, deployer_type, stack, deployer_type,
config, kube_config, config, config_file,
kube_config,
image_registry, image_registry,
output, output,
map_ports_to_host) map_ports_to_host)
@ -272,7 +274,8 @@ def init(ctx, config, kube_config, image_registry, output, map_ports_to_host):
# The init command's implementation is in a separate function so that we can # The init command's implementation is in a separate function so that we can
# call it from other commands, bypassing the click decoration stuff # call it from other commands, bypassing the click decoration stuff
def init_operation(deploy_command_context, stack, deployer_type, config, kube_config, image_registry, output, map_ports_to_host): def init_operation(deploy_command_context, stack, deployer_type, config,
config_file, kube_config, image_registry, output, map_ports_to_host):
yaml = get_yaml() yaml = get_yaml()
default_spec_file_content = call_stack_deploy_init(deploy_command_context) default_spec_file_content = call_stack_deploy_init(deploy_command_context)
spec_file_content = {"stack": stack, constants.deploy_to_key: deployer_type} spec_file_content = {"stack": stack, constants.deploy_to_key: deployer_type}
@ -292,12 +295,22 @@ def init_operation(deploy_command_context, stack, deployer_type, config, kube_co
if default_spec_file_content: if default_spec_file_content:
spec_file_content.update(default_spec_file_content) spec_file_content.update(default_spec_file_content)
config_variables = _parse_config_variables(config) config_variables = _parse_config_variables(config)
# Implement merge, since update() overwrites
if config_variables: if config_variables:
# Implement merge, since update() overwrites
orig_config = spec_file_content.get("config", {}) orig_config = spec_file_content.get("config", {})
new_config = config_variables["config"] new_config = config_variables
merged_config = {**new_config, **orig_config} merged_config = {**new_config, **orig_config}
spec_file_content.update({"config": merged_config}) spec_file_content.update({"config": merged_config})
if config_file:
config_file_path = Path(config_file)
if not config_file_path.exists():
error_exit(f"config file: {config_file} does not exist")
config_file_variables = env_var_map_from_file(config_file_path)
if config_file_variables:
orig_config = spec_file_content.get("config", {})
new_config = config_file_variables
merged_config = {**new_config, **orig_config}
spec_file_content.update({"config": merged_config})
if opts.o.debug: if opts.o.debug:
print(f"Creating spec file for stack: {stack} with content: {spec_file_content}") print(f"Creating spec file for stack: {stack} with content: {spec_file_content}")
@ -368,10 +381,10 @@ def create_operation(deployment_command_context, spec_file, deployment_dir, netw
error_exit(f"{deployment_dir_path} already exists") error_exit(f"{deployment_dir_path} already exists")
os.mkdir(deployment_dir_path) os.mkdir(deployment_dir_path)
# Copy spec file and the stack file into the deployment dir # Copy spec file and the stack file into the deployment dir
copyfile(spec_file, deployment_dir_path.joinpath("spec.yml")) copyfile(spec_file, deployment_dir_path.joinpath(constants.spec_file_name))
copyfile(stack_file, deployment_dir_path.joinpath(os.path.basename(stack_file))) copyfile(stack_file, deployment_dir_path.joinpath(os.path.basename(stack_file)))
# Copy any config varibles from the spec file into an env file suitable for compose # Copy any config varibles from the spec file into an env file suitable for compose
_write_config_file(spec_file, deployment_dir_path.joinpath("config.env")) _write_config_file(spec_file, deployment_dir_path.joinpath(constants.config_file_name))
# Copy any k8s config file into the deployment dir # Copy any k8s config file into the deployment dir
if deployment_type == "k8s": if deployment_type == "k8s":
_write_kube_config_file(Path(parsed_spec[constants.kube_config_key]), _write_kube_config_file(Path(parsed_spec[constants.kube_config_key]),

View File

@ -17,9 +17,10 @@ from kubernetes import client
from typing import Any, List, Set from typing import Any, List, Set
from stack_orchestrator.opts import opts from stack_orchestrator.opts import opts
from stack_orchestrator.util import env_var_map_from_file
from stack_orchestrator.deploy.k8s.helpers import named_volumes_from_pod_files, volume_mounts_for_service, volumes_for_pod_files from stack_orchestrator.deploy.k8s.helpers import named_volumes_from_pod_files, volume_mounts_for_service, volumes_for_pod_files
from stack_orchestrator.deploy.k8s.helpers import get_node_pv_mount_path from stack_orchestrator.deploy.k8s.helpers import get_node_pv_mount_path
from stack_orchestrator.deploy.k8s.helpers import env_var_map_from_file, envs_from_environment_variables_map from stack_orchestrator.deploy.k8s.helpers import envs_from_environment_variables_map
from stack_orchestrator.deploy.deploy_util import parsed_pod_files_map_from_file_names, images_for_deployment from stack_orchestrator.deploy.deploy_util import parsed_pod_files_map_from_file_names, images_for_deployment
from stack_orchestrator.deploy.deploy_types import DeployEnvVars from stack_orchestrator.deploy.deploy_types import DeployEnvVars
from stack_orchestrator.deploy.spec import Spec from stack_orchestrator.deploy.spec import Spec

View File

@ -14,7 +14,6 @@
# along with this program. If not, see <http:#www.gnu.org/licenses/>. # along with this program. If not, see <http:#www.gnu.org/licenses/>.
from kubernetes import client from kubernetes import client
from dotenv import dotenv_values
import os import os
from pathlib import Path from pathlib import Path
import subprocess import subprocess
@ -224,7 +223,3 @@ def generate_kind_config(deployment_dir: Path):
f"{port_mappings_yml}\n" f"{port_mappings_yml}\n"
f"{mounts_yml}\n" f"{mounts_yml}\n"
) )
def env_var_map_from_file(file: Path) -> Mapping[str, str]:
return dotenv_values(file)

View File

@ -98,6 +98,7 @@ def create(ctx, deployment_dir, image, url, kube_config, image_registry, env_fil
stack, stack,
"k8s", "k8s",
None, None,
env_file,
kube_config, kube_config,
image_registry, image_registry,
spec_file_name, spec_file_name,

View File

@ -18,6 +18,8 @@ import os.path
import sys import sys
import ruamel.yaml import ruamel.yaml
from pathlib import Path from pathlib import Path
from dotenv import dotenv_values
from typing import Mapping
def include_exclude_check(s, include, exclude): def include_exclude_check(s, include, exclude):
@ -178,3 +180,7 @@ def global_options2(ctx):
def error_exit(s): def error_exit(s):
print(f"ERROR: {s}") print(f"ERROR: {s}")
sys.exit(1) sys.exit(1)
def env_var_map_from_file(file: Path) -> Mapping[str, str]:
return dotenv_values(file)