WIP: Support wildcard certs. #776
@ -15,6 +15,7 @@
|
||||
|
||||
import click
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from urllib.parse import urlparse
|
||||
from tempfile import NamedTemporaryFile
|
||||
@ -23,6 +24,7 @@ from stack_orchestrator.util import error_exit, global_options2
|
||||
from stack_orchestrator.deploy.deployment_create import init_operation, create_operation
|
||||
from stack_orchestrator.deploy.deploy import create_deploy_context
|
||||
from stack_orchestrator.deploy.deploy_types import DeployCommandContext
|
||||
from stack_orchestrator.deploy.webapp.util import TlsDetails
|
||||
|
||||
|
||||
def _fixup_container_tag(deployment_dir: str, image: str):
|
||||
@ -36,16 +38,16 @@ def _fixup_container_tag(deployment_dir: str, image: str):
|
||||
wfile.write(contents)
|
||||
|
||||
|
||||
def _fixup_url_spec(spec_file_name: str, url: str):
|
||||
def _fixup_url_spec(spec_file_name: str, url: str, tls_details: TlsDetails = TlsDetails()):
|
||||
# url is like: https://example.com/path
|
||||
parsed_url = urlparse(url)
|
||||
http_proxy_spec = f'''
|
||||
http-proxy:
|
||||
http_proxy_spec = f''' http-proxy:
|
||||
- host-name: {parsed_url.hostname}
|
||||
routes:
|
||||
- path: '{parsed_url.path if parsed_url.path else "/"}'
|
||||
proxy-to: webapp:80
|
||||
'''
|
||||
{tls_details.to_yaml(indent=6)}
|
||||
'''
|
||||
spec_file_path = Path(spec_file_name)
|
||||
with open(spec_file_path) as rfile:
|
||||
contents = rfile.read()
|
||||
@ -54,7 +56,8 @@ def _fixup_url_spec(spec_file_name: str, url: str):
|
||||
wfile.write(contents)
|
||||
|
||||
|
||||
def create_deployment(ctx, deployment_dir, image, url, kube_config, image_registry, env_file):
|
||||
def create_deployment(ctx, deployment_dir, image, url, kube_config, image_registry, env_file,
|
||||
tls_details: TlsDetails = None):
|
||||
# Do the equivalent of:
|
||||
# 1. laconic-so --stack webapp-template deploy --deploy-to k8s init --output webapp-spec.yml
|
||||
# --config (eqivalent of the contents of my-config.env)
|
||||
@ -86,7 +89,7 @@ def create_deployment(ctx, deployment_dir, image, url, kube_config, image_regist
|
||||
None
|
||||
)
|
||||
# Add the TLS and DNS spec
|
||||
_fixup_url_spec(spec_file_name, url)
|
||||
_fixup_url_spec(spec_file_name, url, tls_details)
|
||||
create_operation(
|
||||
deploy_command_context,
|
||||
spec_file_name,
|
||||
@ -116,8 +119,16 @@ def command(ctx):
|
||||
@click.option("--image", help="image to deploy", required=True)
|
||||
@click.option("--url", help="url to serve", required=True)
|
||||
@click.option("--env-file", help="environment file for webapp")
|
||||
@click.option("--tls-host", help="Override TLS hostname (eg, '*.mydomain.com')")
|
||||
@click.option("--tls-secret", help="Override TLS secret name")
|
||||
@click.option("--tls-issuer", help="TLS issuer to use (default: letsencrypt-prod)")
|
||||
@click.pass_context
|
||||
def create(ctx, deployment_dir, image, url, kube_config, image_registry, env_file):
|
||||
def create(ctx, deployment_dir, image, url, kube_config, image_registry, env_file, tls_host, tls_secret, tls_issuer):
|
||||
'''create a deployment for the specified webapp container'''
|
||||
|
||||
return create_deployment(ctx, deployment_dir, image, url, kube_config, image_registry, env_file)
|
||||
if (tls_secret and not tls_host) or (tls_host and not tls_secret):
|
||||
print("Cannot specify --tls-host without --tls-secret", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
return create_deployment(ctx, deployment_dir, image, url, kube_config, image_registry, env_file,
|
||||
TlsDetails(tls_host, tls_secret, tls_issuer))
|
||||
|
@ -26,7 +26,7 @@ import click
|
||||
|
||||
from stack_orchestrator.deploy.images import remote_image_exists, add_tags_to_image
|
||||
from stack_orchestrator.deploy.webapp import deploy_webapp
|
||||
from stack_orchestrator.deploy.webapp.util import (LaconicRegistryClient, TimedLogger,
|
||||
from stack_orchestrator.deploy.webapp.util import (LaconicRegistryClient, TimedLogger, TlsDetails,
|
||||
build_container_image, push_container_image,
|
||||
file_hash, deploy_to_k8s, publish_deployment,
|
||||
hostname_for_deployment_request, generate_hostname_for_app,
|
||||
@ -44,7 +44,8 @@ def process_app_deployment_request(
|
||||
kube_config,
|
||||
image_registry,
|
||||
force_rebuild,
|
||||
logger
|
||||
tls_details,
|
||||
logger,
|
||||
):
|
||||
logger.log("BEGIN - process_app_deployment_request")
|
||||
|
||||
@ -198,11 +199,14 @@ def dump_known_requests(filename, requests, status="SEEN"):
|
||||
@click.option("--exclude-tags", help="Exclude requests with matching tags (comma-separated).", default="")
|
||||
@click.option("--force-rebuild", help="Rebuild even if the image already exists.", is_flag=True)
|
||||
@click.option("--log-dir", help="Output build/deployment logs to directory.", default=None)
|
||||
@click.option("--tls-host", help="Override TLS hostname (eg, '*.mydomain.com')")
|
||||
@click.option("--tls-secret", help="Override TLS secret name")
|
||||
@click.option("--tls-issuer", help="TLS issuer to use (default: letsencrypt-prod)")
|
||||
@click.pass_context
|
||||
def command(ctx, kube_config, laconic_config, image_registry, deployment_parent_dir, # noqa: C901
|
||||
request_id, discover, state_file, only_update_state,
|
||||
dns_suffix, record_namespace_dns, record_namespace_deployments, dry_run,
|
||||
include_tags, exclude_tags, force_rebuild, log_dir):
|
||||
include_tags, exclude_tags, force_rebuild, log_dir, tls_host, tls_secret, tls_issuer):
|
||||
if request_id and discover:
|
||||
print("Cannot specify both --request-id and --discover", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
@ -220,6 +224,10 @@ def command(ctx, kube_config, laconic_config, image_registry, deployment_parent_
|
||||
print("--dns-suffix, --record-namespace-dns, and --record-namespace-deployments are all required", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
if (tls_secret and not tls_host) or (tls_host and not tls_secret):
|
||||
print("Cannot specify --tls-host without --tls-secret", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
# Split CSV and clean up values.
|
||||
include_tags = [tag.strip() for tag in include_tags.split(",") if tag]
|
||||
exclude_tags = [tag.strip() for tag in exclude_tags.split(",") if tag]
|
||||
@ -305,6 +313,7 @@ def command(ctx, kube_config, laconic_config, image_registry, deployment_parent_
|
||||
print("Found %d unsatisfied request(s) to process." % len(requests_to_execute))
|
||||
|
||||
if not dry_run:
|
||||
tls_details = TlsDetails(tls_host, tls_secret, tls_issuer)
|
||||
for r in requests_to_execute:
|
||||
dump_known_requests(state_file, [r], "DEPLOYING")
|
||||
status = "ERROR"
|
||||
@ -334,6 +343,7 @@ def command(ctx, kube_config, laconic_config, image_registry, deployment_parent_
|
||||
kube_config,
|
||||
image_registry,
|
||||
force_rebuild,
|
||||
tls_details,
|
||||
logger
|
||||
)
|
||||
status = "DEPLOYED"
|
||||
|
@ -26,6 +26,40 @@ import uuid
|
||||
import yaml
|
||||
|
||||
|
||||
class TlsDetails:
|
||||
def __init__(self, host_or_hosts=None, secret_name: str = None, issuer_name: str = None):
|
||||
if host_or_hosts:
|
||||
if isinstance(host_or_hosts, list):
|
||||
self.hosts = host_or_hosts
|
||||
else:
|
||||
self.hosts = [host_or_hosts]
|
||||
else:
|
||||
self.hosts = None
|
||||
self.secret_name = secret_name
|
||||
self.issuer_name = issuer_name
|
||||
|
||||
def to_yaml(self, indent=6):
|
||||
if not self.hosts and not self.secret_name and not self.issuer_name:
|
||||
return ""
|
||||
|
||||
ret = " " * indent + "tls:\n"
|
||||
indent += 2
|
||||
|
||||
if self.issuer_name:
|
||||
ret += " " * indent + "issuer: '%s'\n" % self.issuer_name
|
||||
|
||||
if self.secret_name:
|
||||
ret += " " * indent + "secret: '%s'\n" % self.secret_name
|
||||
|
||||
if self.hosts:
|
||||
ret += " " * indent + "hosts:"
|
||||
indent += 2
|
||||
for h in self.hosts:
|
||||
ret += "\n" + " " * indent + "- '%s'" % h
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
class AttrDict(dict):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(AttrDict, self).__init__(*args, **kwargs)
|
||||
|
Loading…
Reference in New Issue
Block a user