def deploy_logs(self, env_id): env_id = env_id.lower() http = HttpResponse() docker_utils = DockerUtils() env_id = env_id.strip() env_id_dir = EnvInit.init.get(EnvConstants.DEPLOY_PATH) + f"/{env_id}" file = f"{env_id_dir}/docker-compose.yml" try: status = docker_utils.logs(file) app.logger.debug({"msg": status}) if status.get('err'): raise Exception(status.get('err')) except Exception as e: raise ApiExceptionDocker( ApiCode.GET_LOGS_FAILED.value, ErrorMessage.HTTP_CODE.get(ApiCode.GET_LOGS_FAILED.value) % env_id, e) return Response(json.dumps( http.response(ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), status.get('out'))), 200, mimetype="application/json")
def delete_deployment_id(self, depl_id): depl_id = depl_id.strip() docker_utils = DockerUtils() depl_folder = f"{EnvInit.init.get(EnvConstants.DEPLOY_PATH)}/{depl_id}" file = f"{depl_folder}/docker-compose.yml" try: status = docker_utils.down(file) if "Cannot connect to the Docker daemon".lower() in status.get( 'err').lower(): raise Exception(status.get('err')) app.logger.debug({"msg": status}) status = docker_utils.ps(depl_id) result = status.get('out').split("\n")[1:] DeploymentMetadataSingleton.get_instance( ).delete_metadata_for_deployment(depl_id) IOUtils.remove_directory(f"{depl_folder}") except Exception as e: raise ApiExceptionDocker( ApiCode.DEPLOY_STOP_FAILURE.value, ErrorMessage.HTTP_CODE.get(ApiCode.DEPLOY_STOP_FAILURE.value), e) return Response(json.dumps(HttpResponse().response( ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), result)), 200, mimetype="application/json")
def container_docker_network_connect(self, env_id): env_id = env_id.lower() http = HttpResponse() docker_utils = DockerUtils() headers = request.headers service_name = "container" if request.args.get('service') is not None: service_name = request.args.get('service') container_id = f"{env_id}_{service_name}_1" try: status = CmdUtils.run_cmd_shell_false([ "docker", "network", "ls", "--filter", "name={}".format("deployer") ]) app.logger.debug({"msg": status}) if not status.get('out'): raise Exception(status.get('err')) except Exception as e: raise ApiExceptionDocker( ApiCode.GET_DEPLOYER_NETWORK_FAILED.value, ErrorMessage.HTTP_CODE.get( ApiCode.GET_DEPLOYER_NETWORK_FAILED.value), e) try: deployer_network = status.get('out').split("\n")[1].split( " ")[0].strip() if headers.get("Docker-Network"): deployer_network = headers.get("Docker-Network") status = docker_utils.network_connect(deployer_network, container_id) if "already exists in network".lower() in status.get( 'err').lower(): return Response(json.dumps( http.response( ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), "Success, already connected: " + status.get('err'))), 200, mimetype="application/json") if "Error response from daemon".lower() in status.get( 'err').lower(): raise Exception(status.get('err')) except Exception as e: raise ApiExceptionDocker( ApiCode.CONTAINER_NET_CONNECT_FAILED.value, ErrorMessage.HTTP_CODE.get( ApiCode.CONTAINER_NET_CONNECT_FAILED.value), e) return Response(json.dumps( http.response(ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), status.get('out'))), 200, mimetype="application/json")
def get_active_deployments(self): docker_utils = DockerUtils() active_deployments = docker_utils.get_active_deployments() app.logger.debug( {"msg": { "active_deployments": f"{len(active_deployments)}" }}) return Response(json.dumps(HttpResponse().response( ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), active_deployments)), 200, mimetype="application/json")
def delete_all_deployments(self): docker_utils = DockerUtils() try: active_deployments = docker_utils.get_active_deployments() for deployment in active_deployments: depl_id = deployment.get('id') depl_folder = f"{EnvInit.init.get(EnvConstants.DEPLOY_PATH)}/{depl_id}" status = docker_utils.down(f"{depl_folder}/docker-compose.yml") if "Cannot connect to the Docker daemon".lower() in status.get( 'err').lower(): raise Exception(status.get('err')) app.logger.debug({"msg": status}) DeploymentMetadataSingleton.get_instance( ).delete_metadata_for_deployment(depl_id) DockerUtils.folder_clean_up() result = docker_utils.get_active_deployments() except Exception as e: raise ApiExceptionDocker( ApiCode.DEPLOY_STOP_FAILURE.value, ErrorMessage.HTTP_CODE.get(ApiCode.DEPLOY_STOP_FAILURE.value), e) return Response(json.dumps(HttpResponse().response( ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), result)), 200, mimetype="application/json")
def get_deployment_status(self, env_id): env_id = env_id.lower() docker_utils = DockerUtils() env_id = env_id.strip() try: status = docker_utils.ps(env_id) if "Cannot connect to the Docker daemon".lower() in status.get( 'err').lower(): raise Exception(status.get('err')) result = status.get('out').split("\n")[1:] app.logger.debug({"msg": status}) except Exception as e: raise ApiExceptionDocker( ApiCode.DEPLOY_STATUS_FAILURE.value, ErrorMessage.HTTP_CODE.get( ApiCode.DEPLOY_STATUS_FAILURE.value), e) return Response(json.dumps(HttpResponse().response( ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), ActiveDeployment.docker_deployment(env_id, result))), 200, mimetype="application/json")
def cleanup_inactive_deployments(self): """ ! can be executed only after /deployments DELETE ! """ try: deleted_folders = DockerUtils.folder_clean_up() except Exception as e: raise ApiExceptionDocker( ApiCode.DEPLOYMENTS_FOLDER_CLEANUP_FAILURE.value, ErrorMessage.HTTP_CODE.get( ApiCode.DEPLOYMENTS_FOLDER_CLEANUP_FAILURE.value), e) return Response(json.dumps(HttpResponse().response( ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), deleted_folders)), 200, mimetype="application/json")
def start_deployment_with_templates(self, template, variables): http = HttpResponse() docker_utils = DockerUtils() token = token_hex(8) deployment_id = request.headers.get("Deployment-Id").lower( ) if request.headers.get("Deployment-Id") else token deploy_dir = f"{EnvInit.init.get(EnvConstants.DEPLOY_PATH)}/{deployment_id}" file = f"{deploy_dir}/docker-compose.yml" try: input_json = request.get_json(force=True) for key, value in input_json.items(): if key not in EnvironmentSingleton.get_instance().get_env(): EnvironmentSingleton.get_instance().set_env_var( str(key), str(value)) except Exception as e: app.logger.debug( f"Could not parse the input from the request as JSON: {e.__str__()}" ) EnvironmentSingleton.get_instance().set_env_var( EnvConstants.TEMPLATE, template.strip()) EnvironmentSingleton.get_instance().set_env_var( EnvConstants.VARIABLES, variables.strip()) env_vars = EnvironmentSingleton.get_instance().get_env_and_virtual_env( ) app.logger.debug( {"msg": { "template_file": env_vars.get(EnvConstants.TEMPLATE) }}) app.logger.debug( {"msg": { "variables_file": env_vars.get(EnvConstants.VARIABLES) }}) status = CmdUtils.run_cmd_shell_false(["docker", "ps"]) if "Cannot connect to the Docker daemon".lower() in status.get( 'err').lower(): raise ApiExceptionDocker( ApiCode.DOCKER_DAEMON_NOT_RUNNING.value, ErrorMessage.HTTP_CODE.get( ApiCode.DOCKER_DAEMON_NOT_RUNNING.value), status.get('err')) active_deployments = docker_utils.get_active_deployments() if len(active_deployments) >= EnvInit.init.get( EnvConstants.MAX_DEPLOYMENTS): raise ApiExceptionDocker( ApiCode.MAX_DEPLOYMENTS_REACHED.value, ErrorMessage.HTTP_CODE.get( ApiCode.MAX_DEPLOYMENTS_REACHED.value) % str(EnvInit.init.get(EnvConstants.MAX_DEPLOYMENTS)), active_deployments) try: r = Render(env_vars.get(EnvConstants.TEMPLATE), env_vars.get(EnvConstants.VARIABLES)) IOUtils.create_dir(deploy_dir) IOUtils.write_to_file(file, r.rend_template()) CmdUtils.run_cmd_detached( rf'''docker-compose -f {file} pull && docker-compose -f {file} up -d''' ) except Exception as e: raise ApiExceptionDocker( ApiCode.DEPLOY_START_FAILURE.value, ErrorMessage.HTTP_CODE.get(ApiCode.DEPLOY_START_FAILURE.value), e) DeploymentMetadataSingleton.get_instance() \ .delete_metadata_for_inactive_deployments(DockerUtils.get_active_deployments()) metadata = DeploymentReader.get_metadata_for_deployment( IOUtils.read_file(file=file)) IOUtils.write_to_file_dict(f"{deploy_dir}/metadata.json", metadata) DeploymentMetadataSingleton.get_instance().set_metadata_for_deployment( deployment_id, metadata) return Response(json.dumps( http.response(ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), deployment_id)), 200, mimetype="application/json")
def start_deployment(self): docker_utils = DockerUtils() token = token_hex(8) deployment_id = request.headers.get("Deployment-Id").lower( ) if request.headers.get("Deployment-Id") else token deploy_dir = f"{EnvInit.init.get(EnvConstants.DEPLOY_PATH)}/{deployment_id}" file = f"{deploy_dir}/docker-compose.yml" header_key = 'Eureka-Server' eureka_server_header = request.headers.get(f"{header_key}") config_env_vars = EnvStartupSingleton.get_instance( ).get_config_env_vars() input_data = request.data.decode('UTF-8').strip() status = CmdUtils.run_cmd_shell_false(["docker", "ps"]) if "Cannot connect to the Docker daemon".lower() in status.get( 'err').lower(): raise ApiExceptionDocker( ApiCode.DOCKER_DAEMON_NOT_RUNNING.value, ErrorMessage.HTTP_CODE.get( ApiCode.DOCKER_DAEMON_NOT_RUNNING.value), status.get('err')) active_deployments = docker_utils.get_active_deployments() if len(active_deployments) >= EnvInit.init.get( EnvConstants.MAX_DEPLOYMENTS): raise ApiExceptionDocker( ApiCode.MAX_DEPLOYMENTS_REACHED.value, ErrorMessage.HTTP_CODE.get( ApiCode.MAX_DEPLOYMENTS_REACHED.value) % str(EnvInit.init.get(EnvConstants.MAX_DEPLOYMENTS)), active_deployments) try: template_file_name = f"deployment_{deployment_id}.yml" template_file_path = f"{EnvInit.init.get(EnvConstants.TEMPLATES_DIR)}/{template_file_name}" app.logger.debug({ "msg": { "file": template_file_path, "file_content": f"{input_data}" } }) IOUtils.write_to_file(template_file_path, input_data) IOUtils.create_dir(deploy_dir) EnvironmentSingleton.get_instance().set_env_var( EnvConstants.TEMPLATE, template_file_name) env_vars = EnvironmentSingleton.get_instance( ).get_env_and_virtual_env() render = Render(env_vars.get(EnvConstants.TEMPLATE), env_vars.get(EnvConstants.VARIABLES)) if config_env_vars.get( EnvConstants.EUREKA_SERVER) and config_env_vars.get( EnvConstants.APP_IP_PORT): # if {{app_ip_port}} and {{eureka_server}} then register that instance too if '{{app_ip_port}}' in input_data and '{{eureka_server}}' in input_data: eureka_server = config_env_vars.get( EnvConstants.EUREKA_SERVER) # header value overwrite the eureka server if eureka_server_header: eureka_server = eureka_server_header input_data = render.get_jinja2env().get_template( env_vars.get(EnvConstants.TEMPLATE)).render({ "deployment_id": f"{deployment_id}", "eureka_server": eureka_server, "app_ip_port": config_env_vars.get( EnvConstants.APP_IP_PORT).split("/")[0] }) os.remove(template_file_path) if os.path.exists( template_file_path) else None app.logger.debug( {"msg": { "file": file, "file_content": f"{input_data}" }}) IOUtils.write_to_file(file, input_data) if input_data else None CmdUtils.run_cmd_detached( rf'''docker-compose -f {file} pull && docker-compose -f {file} up -d''' ) except Exception as e: app.logger.debug({"msg": docker_utils.down(file)}) raise ApiExceptionDocker( ApiCode.DEPLOY_START_FAILURE.value, ErrorMessage.HTTP_CODE.get(ApiCode.DEPLOY_START_FAILURE.value), e) DeploymentMetadataSingleton.get_instance() \ .delete_metadata_for_inactive_deployments(DockerUtils.get_active_deployments()) metadata = DeploymentReader.get_metadata_for_deployment( IOUtils.read_file(file=file)) IOUtils.write_to_file_dict(f"{deploy_dir}/metadata.json", metadata) DeploymentMetadataSingleton.get_instance().set_metadata_for_deployment( deployment_id, metadata) return Response(json.dumps(HttpResponse().response( ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), deployment_id)), 200, mimetype="application/json")