Add 'update' command as well

This commit is contained in:
Thomas E Lackey 2023-12-05 15:13:32 -06:00
parent 86c962e0cf
commit 1ded4cec81
7 changed files with 63 additions and 11 deletions

View File

@ -40,6 +40,12 @@ class DockerDeployer(Deployer):
except DockerException as e: except DockerException as e:
raise DeployerException(e) raise DeployerException(e)
def update(self):
try:
return self.docker.compose.restart()
except DockerException as e:
raise DeployerException(e)
def ps(self): def ps(self):
try: try:
return self.docker.compose.ps() 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) 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): def ps_operation(ctx):
global_context = ctx.parent.parent.obj global_context = ctx.parent.parent.obj
if not global_context.dry_run: if not global_context.dry_run:

View File

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

View File

@ -19,7 +19,7 @@ import sys
from stack_orchestrator import constants from stack_orchestrator import constants
from stack_orchestrator.deploy.images import push_images_operation 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 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.deploy_types import DeployCommandContext
from stack_orchestrator.deploy.deployment_context import DeploymentContext from stack_orchestrator.deploy.deployment_context import DeploymentContext
from stack_orchestrator.deploy.webapp import update_from_registry as webapp_update 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): def update_from_registry(ctx, laconic_config, app_crn, deployment_crn, force):
ctx.obj = make_deploy_context(ctx) ctx.obj = make_deploy_context(ctx)
webapp_update.update(ctx, str(ctx.obj.stack.parent), laconic_config, app_crn, deployment_crn, force) 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( container = client.V1Container(
name=container_name, name=container_name,
image=image_to_use, image=image_to_use,
image_pull_policy="Always",
env=envs_from_environment_variables_map(self.environment_variables.map), env=envs_from_environment_variables_map(self.environment_variables.map),
ports=[client.V1ContainerPort(container_port=port)], ports=[client.V1ContainerPort(container_port=port)],
volume_mounts=volume_mounts, volume_mounts=volume_mounts,

View File

@ -13,6 +13,8 @@
# You should have received a copy of the GNU Affero General Public License # 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/>. # along with this program. If not, see <http:#www.gnu.org/licenses/>.
from datetime import datetime, timezone
from pathlib import Path from pathlib import Path
from kubernetes import client, config from kubernetes import client, config
@ -42,7 +44,7 @@ class K8sDeployer(Deployer):
networking_api: client.NetworkingV1Api networking_api: client.NetworkingV1Api
k8s_namespace: str = "default" k8s_namespace: str = "default"
kind_cluster_name: str kind_cluster_name: str
cluster_info : ClusterInfo cluster_info: ClusterInfo
deployment_dir: Path deployment_dir: Path
deployment_context: DeploymentContext 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") log_data = self.core_api.read_namespaced_pod_log(k8s_pod_name, namespace="default", container="test")
return log_stream_from_string(log_data) 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): 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 # We need to figure out how to do this -- check why we're being called first
pass 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): def redeploy(laconic_config, app_record, deploy_record, deploy_crn, deployment_dir):
print("Stopping deployment ...") print("Updating deployment ...")
result = subprocess.run(["laconic-so", "deployment", "--dir", deployment_dir, "stop"]) result = subprocess.run(["laconic-so", "deployment", "--dir", deployment_dir, "update"])
result.check_returncode()
print("Starting deployment ...")
result = subprocess.run(["laconic-so", "deployment", "--dir", deployment_dir, "start"])
result.check_returncode() result.check_returncode()
spec = yaml.full_load(open(os.path.join(deployment_dir, "spec.yml"))) 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"): if app_record["id"] == deploy_record.get("attributes", {}).get("application"):
print("Deployment %s has latest application: %s" % (deploy_crn, app_record["id"])) print("Deployment %s has latest application: %s" % (deploy_crn, app_record["id"]))
else: else:
needs_update = True
print("Found updated application record eligible for deployment %s (old: %s, new: %s)" % ( print("Found updated application record eligible for deployment %s (old: %s, new: %s)" % (
deploy_crn, deploy_record.get("id"), app_record["id"])) deploy_crn, deploy_record.get("id"), app_record["id"]))
build_image(app_record, deployment_dir) build_image(app_record, deployment_dir)
needs_update = True
# check config # check config
if config_changed(deploy_record, deployment_dir): if config_changed(deploy_record, deployment_dir):
needs_update = True
old = None old = None
if deploy_record: 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)" % ( print("Deployment %s has changed config: (old: %s, new: %s)" % (
deploy_crn, old, config_hash(deployment_dir))) deploy_crn, old, config_hash(deployment_dir)))
needs_update = True
else: else:
print("Deployment %s has latest config: %s" % ( print("Deployment %s has latest config: %s" % (
deploy_crn, json.loads(deploy_record["attributes"]["meta"])["config"])) deploy_crn, json.loads(deploy_record["attributes"]["meta"])["config"]))