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 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 before_request(self, name, *args, **kwargs): ctx = app.app_context() ctx.g.xid = token_hex(8) http = HttpResponse() request_uri = request.full_path # add here your custom header to be logged with fluentd self.message_dumper.set_header( HeaderConstants.X_REQUEST_ID, request.headers.get(HeaderConstants.X_REQUEST_ID) if request.headers.get(HeaderConstants.X_REQUEST_ID) else ctx.g.xid) self.message_dumper.set_header(HeaderConstants.REQUEST_URI, request_uri) response = self.fluentd.emit( tag="api", msg=self.message_dumper.dump(request=request)) app.logger.debug(response) if not str(request.headers.get(HeaderConstants.TOKEN)) == str( EnvStartupSingleton.get_instance().get_config_env_vars().get( EnvConstants.HTTP_AUTH_TOKEN)): if not ("/apidocs" in request_uri or "/swagger/swagger.json" in request_uri): # exclude swagger headers = { HeaderConstants.X_REQUEST_ID: self.message_dumper.get_header( HeaderConstants.X_REQUEST_ID) } return Response(json.dumps( http.response( ApiCode.UNAUTHORIZED.value, ErrorMessage.HTTP_CODE.get(ApiCode.UNAUTHORIZED.value), "Invalid Token")), 401, mimetype="application/json", headers=headers)
def set_env(): http = HttpResponse() input_data = request.data.decode("UTF-8", "replace").strip() try: env_vars_attempted = json.loads(input_data) except Exception as e: raise ApiException( ApiCode.INVALID_JSON_PAYLOAD.value, ErrorMessage.HTTP_CODE.get(ApiCode.INVALID_JSON_PAYLOAD.value) % str(input_data), e) try: for key, value in env_vars_attempted.items(): env.set_env_var(key, value) env_vars_added = { key: value for key, value in env_vars_attempted.items() if key in env.get_virtual_env() } except Exception as e: raise ApiException( ApiCode.SET_ENV_VAR_FAILURE.value, ErrorMessage.HTTP_CODE.get(ApiCode.SET_ENV_VAR_FAILURE.value) % str(input_data), e) return Response(json.dumps( http.response(ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), env_vars_added)), 200, mimetype="application/json")
def get_deployment_status(self, pod): http = HttpResponse() pod = pod.strip() kubectl_utils = KubectlUtils() header_keys = ["Label-Selector", 'K8s-Namespace'] for header_key in header_keys: if not request.headers.get(f"{header_key}"): raise ApiExceptionKubectl( ApiCode.HTTP_HEADER_NOT_PROVIDED.value, ErrorMessage.HTTP_CODE.get( ApiCode.HTTP_HEADER_NOT_PROVIDED.value) % header_key, ErrorMessage.HTTP_CODE.get( ApiCode.HTTP_HEADER_NOT_PROVIDED.value) % header_key) try: label_selector = request.headers.get(f"{header_keys[0]}") namespace = request.headers.get(f"{header_keys[1]}") deployment = kubectl_utils.get_active_pod(pod, label_selector, namespace) except Exception as e: raise ApiExceptionKubectl( ApiCode.DEPLOY_STATUS_FAILURE.value, ErrorMessage.HTTP_CODE.get( ApiCode.DEPLOY_STATUS_FAILURE.value), e) return Response(json.dumps( http.response(ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), deployment)), 200, mimetype="application/json")
def deploy_logs(self, deployment): http = HttpResponse() kubectl_utils = KubectlUtils() deployment = deployment.strip() header_key = 'K8s-Namespace' if not request.headers.get(f"{header_key}"): raise ApiExceptionKubectl( ApiCode.HTTP_HEADER_NOT_PROVIDED.value, ErrorMessage.HTTP_CODE.get( ApiCode.HTTP_HEADER_NOT_PROVIDED.value) % header_key, ErrorMessage.HTTP_CODE.get( ApiCode.HTTP_HEADER_NOT_PROVIDED.value) % header_key) try: if request.headers.get(f"{header_key}"): namespace = request.headers.get(f"{header_key}") status = kubectl_utils.logs(deployment, namespace) if status.get('err'): raise Exception(status) except Exception as e: raise ApiExceptionKubectl( ApiCode.GET_LOGS_FAILED.value, ErrorMessage.HTTP_CODE.get(ApiCode.GET_LOGS_FAILED.value) % deployment, 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(self, deployment): http = HttpResponse() deployment = deployment.strip() kubectl_utils = KubectlUtils() header_key = 'K8s-Namespace' fluentd_tag = "deploy_stop" if not request.headers.get(f"{header_key}"): raise ApiExceptionKubectl( ApiCode.HTTP_HEADER_NOT_PROVIDED.value, ErrorMessage.HTTP_CODE.get( ApiCode.HTTP_HEADER_NOT_PROVIDED.value) % header_key, ErrorMessage.HTTP_CODE.get( ApiCode.HTTP_HEADER_NOT_PROVIDED.value) % header_key) try: namespace = request.headers.get(f"{header_key}") status = kubectl_utils.down(deployment, namespace) self.fluentd.emit(tag=fluentd_tag, msg={"msg": status}) if "Error".lower() in status.get('err').lower(): raise Exception(status.get('err')) result = status.get('out').split("\n")[1:] except Exception as e: raise ApiExceptionKubectl( ApiCode.DEPLOY_STOP_FAILURE.value, ErrorMessage.HTTP_CODE.get(ApiCode.DEPLOY_STOP_FAILURE.value), e) return Response(json.dumps( http.response(ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), result)), 200, mimetype="application/json")
def deploy_start(self): http = HttpResponse() kubectl_utils = KubectlUtils() fluentd_tag = "deploy_start" token = token_hex(8) deploy_dir = f"{EnvInit.init.get(EnvConstants.DEPLOY_PATH)}/{token}" file = f"{deploy_dir}/k8s-deployment.yml" try: IOUtils.create_dir(deploy_dir) input_data = request.data.decode('utf-8') IOUtils.write_to_file(file, input_data) status = kubectl_utils.up(f"{file}") self.fluentd.emit(tag=fluentd_tag, msg={"msg": status}) if status.get('err'): raise Exception(status.get('err')) except Exception as e: raise ApiExceptionKubectl( ApiCode.DEPLOY_START_FAILURE.value, ErrorMessage.HTTP_CODE.get(ApiCode.DEPLOY_START_FAILURE.value), e) return Response(json.dumps( http.response(ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), token)), 200, mimetype="application/json")
def get_deployment_info(self): http = HttpResponse() kubectl_utils = KubectlUtils() header_keys = ["Label-Selector", 'K8s-Namespace'] for header_key in header_keys: if not request.headers.get(f"{header_key}"): raise ApiExceptionKubectl( ApiCode.HTTP_HEADER_NOT_PROVIDED.value, ErrorMessage.HTTP_CODE.get( ApiCode.HTTP_HEADER_NOT_PROVIDED.value) % header_key, ErrorMessage.HTTP_CODE.get( ApiCode.HTTP_HEADER_NOT_PROVIDED.value) % header_key) label_selector = request.headers.get(f"{header_keys[0]}") namespace = request.headers.get(f"{header_keys[1]}") active_pods = kubectl_utils.get_active_pods(label_selector, namespace) app.logger.debug( {"msg": { "active_deployments": f"{len(active_pods)}" }}) return Response(json.dumps( http.response(ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), active_pods)), 200, mimetype="application/json")
def set_env(self): http = HttpResponse() input_data = request.data.decode("UTF-8", "replace").strip() try: env_vars_attempted = json.loads(input_data) except Exception as e: raise ApiExceptionKubectl( ApiCode.INVALID_JSON_PAYLOAD.value, ErrorMessage.HTTP_CODE.get(ApiCode.INVALID_JSON_PAYLOAD.value) % str(input_data), e) try: env_vars_added = EnvironmentSingleton.get_instance().set_env_vars( env_vars_attempted) except Exception as e: raise ApiExceptionKubectl( ApiCode.SET_ENV_VAR_FAILURE.value, ErrorMessage.HTTP_CODE.get(ApiCode.SET_ENV_VAR_FAILURE.value) % str(input_data), e) return Response(json.dumps( http.response(ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), env_vars_added)), 200, mimetype="application/json")
def get_eureka_apps(): http = HttpResponse() eureka = Eureka( EnvStartupSingleton.get_instance().get_config_env_vars().get( EnvConstants.EUREKA_SERVER)) try: apps_list = eureka.get_eureka_apps() except Exception as e: raise ApiException( ApiCode.GET_EUREKA_APPS_FAILED.value, ErrorMessage.HTTP_CODE.get(ApiCode.GET_EUREKA_APPS_FAILED.value) % eureka.get_eureka_host(), e) return Response(json.dumps( http.response(ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), apps_list)), 200, mimetype="application/json")
def upload_file(self): http = HttpResponse() io_utils = IOUtils() header_key = 'File-Path' file_content = request.get_data() file_path = request.headers.get(f"{header_key}") if not file_path: raise ApiExceptionDocker( ApiCode.HTTP_HEADER_NOT_PROVIDED.value, ErrorMessage.HTTP_CODE.get( ApiCode.HTTP_HEADER_NOT_PROVIDED.value) % header_key, ErrorMessage.HTTP_CODE.get( ApiCode.HTTP_HEADER_NOT_PROVIDED.value) % header_key) if not file_content: raise ApiExceptionDocker( ApiCode.EMPTY_REQUEST_BODY_PROVIDED.value, ErrorMessage.HTTP_CODE.get( ApiCode.EMPTY_REQUEST_BODY_PROVIDED.value), ErrorMessage.HTTP_CODE.get( ApiCode.EMPTY_REQUEST_BODY_PROVIDED.value)) try: io_utils.write_to_file_binary(file_path, file_content) except Exception as e: raise ApiExceptionDocker( ApiCode.UPLOAD_FILE_FAILURE.value, ErrorMessage.HTTP_CODE.get(ApiCode.UPLOAD_FILE_FAILURE.value), e) return Response(json.dumps( http.response(ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value))), 200, mimetype="application/json")
def send_http_request(self, app, request_object): logging.debug({ "url": f'{self.get_url(app)}{request_object.get("uri")}', "method": request_object.get('method'), "headers": request_object.get("headers"), "data": request_object.get("data") }) try: response = requests.request( method=request_object.get('method'), url=f'{self.get_url(app)}{request_object.get("uri")}', headers=request_object.get("headers"), data=request_object.get('data'), timeout=10, verify=False) except Exception as e: response = HttpResponse.response( ApiCode.TARGET_UNREACHABLE.value, ErrorMessage.HTTP_CODE.get(ApiCode.TARGET_UNREACHABLE.value) % f'{self.get_url(app)}{request_object.get("uri")}', "Exception({})".format(e.__str__())) return response
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_with_template(self, template, variables): http = HttpResponse() kubectl_utils = KubectlUtils() fluentd_tag = "deploy_start" 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"Exception: {e.__str__()}") EnvironmentSingleton.get_instance().set_env_var( EnvConstants.TEMPLATE, template.strip()) EnvironmentSingleton.get_instance().set_env_var( EnvConstants.VARIABLES, variables.strip()) app.logger.debug({ "msg": { "template_file": EnvironmentSingleton.get_instance().get_env_and_virtual_env(). get(EnvConstants.TEMPLATE) } }) app.logger.debug({ "msg": { "variables_file": EnvironmentSingleton.get_instance().get_env_and_virtual_env(). get(EnvConstants.VARIABLES) } }) token = token_hex(8) deploy_dir = f"{EnvInit.init.get(EnvConstants.DEPLOY_PATH)}/{token}" file = f"{deploy_dir}/k8s-deployment.yml" try: r = Render( EnvironmentSingleton.get_instance().get_env_and_virtual_env( ).get(EnvConstants.TEMPLATE), EnvironmentSingleton.get_instance().get_env_and_virtual_env(). get(EnvConstants.VARIABLES)) IOUtils.create_dir(deploy_dir) IOUtils.write_to_file(file) IOUtils.write_to_file(file, r.rend_template()) status = kubectl_utils.up(f"{file}") self.fluentd.emit(tag=fluentd_tag, msg={"msg": status}) if status.get('err'): raise Exception(status.get('error')) result = str(token) except Exception as e: raise ApiExceptionKubectl( ApiCode.DEPLOY_START_FAILURE.value, ErrorMessage.HTTP_CODE.get(ApiCode.DEPLOY_START_FAILURE.value), e) return Response(json.dumps( http.response(ApiCode.SUCCESS.value, ErrorMessage.HTTP_CODE.get(ApiCode.SUCCESS.value), result)), 200, mimetype="application/json")