Add deployment update and deploy-webapp-from-registry commands. #676

Merged
telackey merged 23 commits from telackey/deployer into main 2023-12-14 03:02:34 +00:00
7 changed files with 63 additions and 11 deletions
Showing only changes of commit 1ded4cec81 - Show all commits

View File

@ -40,6 +40,12 @@ class DockerDeployer(Deployer):
except DockerException as e:
raise DeployerException(e)
def update(self):
try:
return self.docker.compose.restart()
except DockerException as e:
raise DeployerException(e)
def ps(self):
try:
return self.docker.compose.ps()

View File

@ -107,6 +107,14 @@ def down_operation(ctx, delete_volumes, extra_args_list):
ctx.obj.deployer.down(timeout=timeout_arg, volumes=delete_volumes)
def update_operation(ctx):
global_context = ctx.parent.parent.obj
if not global_context.dry_run:
if global_context.verbose:
print("Running compose update")
ctx.obj.deployer.update()
def ps_operation(ctx):
global_context = ctx.parent.parent.obj
if not global_context.dry_run:

View File

@ -27,6 +27,10 @@ class Deployer(ABC):
def down(self, timeout, volumes):
pass
@abstractmethod
def update(self):
pass
@abstractmethod
def ps(self):
pass

View File

@ -19,7 +19,7 @@ import sys
from stack_orchestrator import constants
from stack_orchestrator.deploy.images import push_images_operation
from stack_orchestrator.deploy.deploy import up_operation, down_operation, ps_operation, port_operation
from stack_orchestrator.deploy.deploy import exec_operation, logs_operation, create_deploy_context
from stack_orchestrator.deploy.deploy import exec_operation, logs_operation, create_deploy_context, update_operation
from stack_orchestrator.deploy.deploy_types import DeployCommandContext
from stack_orchestrator.deploy.deployment_context import DeploymentContext
from stack_orchestrator.deploy.webapp import update_from_registry as webapp_update
@ -161,3 +161,10 @@ def status(ctx):
def update_from_registry(ctx, laconic_config, app_crn, deployment_crn, force):
ctx.obj = make_deploy_context(ctx)
webapp_update.update(ctx, str(ctx.obj.stack.parent), laconic_config, app_crn, deployment_crn, force)
@command.command()
@click.pass_context
def update(ctx):
ctx.obj = make_deploy_context(ctx)
update_operation(ctx)

View File

@ -189,6 +189,7 @@ class ClusterInfo:
container = client.V1Container(
name=container_name,
image=image_to_use,
image_pull_policy="Always",
env=envs_from_environment_variables_map(self.environment_variables.map),
ports=[client.V1ContainerPort(container_port=port)],
volume_mounts=volume_mounts,

View File

@ -13,6 +13,8 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http:#www.gnu.org/licenses/>.
from datetime import datetime, timezone
from pathlib import Path
from kubernetes import client, config
@ -42,7 +44,7 @@ class K8sDeployer(Deployer):
networking_api: client.NetworkingV1Api
k8s_namespace: str = "default"
kind_cluster_name: str
cluster_info : ClusterInfo
cluster_info: ClusterInfo
deployment_dir: Path
deployment_context: DeploymentContext
@ -230,6 +232,33 @@ class K8sDeployer(Deployer):
log_data = self.core_api.read_namespaced_pod_log(k8s_pod_name, namespace="default", container="test")
return log_stream_from_string(log_data)
def update(self):
self.connect_api()
ref_deployment = self.cluster_info.get_deployment()
deployment = self.apps_api.read_namespaced_deployment(
name=ref_deployment.metadata.name,
namespace=self.k8s_namespace
)
new_env = ref_deployment.spec.template.spec.containers[0].env
for container in deployment.spec.template.spec.containers:
old_env = container.env
if old_env != new_env:
container.env = new_env
deployment.spec.template.metadata.annotations = {
"kubectl.kubernetes.io/restartedAt": datetime.utcnow()
.replace(tzinfo=timezone.utc)
.isoformat()
}
self.apps_api.patch_namespaced_deployment(
name=ref_deployment.metadata.name,
namespace=self.k8s_namespace,
body=deployment
)
def run(self, image: str, command=None, user=None, volumes=None, entrypoint=None, env={}, ports=[], detach=False):
# We need to figure out how to do this -- check why we're being called first
pass

View File

@ -74,12 +74,8 @@ def config_changed(deploy_record, deployment_dir):
def redeploy(laconic_config, app_record, deploy_record, deploy_crn, deployment_dir):
print("Stopping deployment ...")
result = subprocess.run(["laconic-so", "deployment", "--dir", deployment_dir, "stop"])
result.check_returncode()
print("Starting deployment ...")
result = subprocess.run(["laconic-so", "deployment", "--dir", deployment_dir, "start"])
print("Updating deployment ...")
result = subprocess.run(["laconic-so", "deployment", "--dir", deployment_dir, "update"])
result.check_returncode()
spec = yaml.full_load(open(os.path.join(deployment_dir, "spec.yml")))
@ -143,19 +139,20 @@ def update(ctx, deployment_dir, laconic_config, app_crn, deploy_crn, force=False
if app_record["id"] == deploy_record.get("attributes", {}).get("application"):
print("Deployment %s has latest application: %s" % (deploy_crn, app_record["id"]))
else:
needs_update = True
print("Found updated application record eligible for deployment %s (old: %s, new: %s)" % (
deploy_crn, deploy_record.get("id"), app_record["id"]))
build_image(app_record, deployment_dir)
needs_update = True
# check config
if config_changed(deploy_record, deployment_dir):
needs_update = True
old = None
if deploy_record:
old = json.loads(deploy_record["attributes"]["meta"]["config"])
print(deploy_record)
old = json.loads(deploy_record["attributes"]["meta"])["config"]
print("Deployment %s has changed config: (old: %s, new: %s)" % (
deploy_crn, old, config_hash(deployment_dir)))
needs_update = True
else:
print("Deployment %s has latest config: %s" % (
deploy_crn, json.loads(deploy_record["attributes"]["meta"])["config"]))