Files
svc-api-x/v1/resources/instance_operation_run.cfc
T

441 lines
20 KiB
Plaintext

<cfcomponent extends="taffy.core.resource" taffy:uri="/instanceOperations/{instanceOperationUid}/run">
<cfsilent>
<cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
</cfsilent>
<cffunction name="post" hint="Запуск выполнения операции">
<cfargument name="instanceOperationUid" type="string" required=true hint="type:guid"/>
<cfset var local={}/>
<cftry>
<cfset this.helper.keyExistsAndValid(arguments, "instanceOperationUid", "guid")/>
<cfquery name="local.qCheckAccess" result="local.result">
select count(*) as cnt
from instance_operation io
join instance e on (io.instance_uid=e.instance_uid)
join specification_item si on (e.specification_item_id=si.specification_item_id)
where io.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#" null=#!isValid('guid',arguments.instanceOperationUid)#/>
AND si.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
</cfquery>
<cfif local.qCheckAccess.cnt EQ 0>
<cfreturn representationOf(this.helper.formatMessage("Instance not accessible", "Instance is not accessible to the current user (at least does not belong to the default specification)")).withStatus(403)/>
</cfif>
<cfquery name="local.qSvcOperation" result="local.result">
select io.operation, s.svc_id, so.svc_operation_id
from instance_operation io
join instance e on (io.instance_uid=e.instance_uid)
join svc s on (e.service_id=s.svc_id)
join svc_operation so on (s.svc_id=so.svc_id AND io.operation=so.operation)
where io.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#" null=#!isValid('guid',arguments.instanceOperationUid)#/>
</cfquery>
<cfquery name="local.qInstance" result="local.result">
select io.instance_uid
from instance_operation io
where io.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#" null=#!isValid('guid',arguments.instanceOperationUid)#/>
</cfquery>
<cfquery name="local.qCheckStartedCurrentOp" result="local.result">
select io.dt_submit, io.dt_finish, io.dt_start, io.submit_result, io.status_url
from instance_operation io
where io.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#" null=#!isValid('guid',arguments.instanceOperationUid)#/>
</cfquery>
<cfif local.qCheckStartedCurrentOp.recordCount EQ 0>
<cfreturn representationOf(this.helper.formatMessage(
"There is no configured instance operation with uid #arguments.instanceOperationUid#",
"Instance operation not found")
).withStatus(404)/>
</cfif>
<cfquery name="local.qCheckStarted" result="local.result">
select io.dt_submit, io.dt_finish, io.dt_start, io.submit_result, io.status_url
from instance_operation io
where io.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#local.qInstance.instance_uid#" null=#!isValid('guid',local.qInstance.instance_uid)#/>
AND left(io.submit_result,1)='2' AND io.dt_finish IS NULL
</cfquery>
<cfloop query="local.qCheckStarted">
<cfset var jobStatus = getJobStatus(local.qCheckStarted.status_url)/>
<cfif (jobStatus EQ 'FAILED') OR (jobStatus EQ 'ABORTED')>
<cfquery name="local.qMarkFailed">
update instance_operation
set is_successful=false, dt_finish=CURRENT_TIMESTAMP
where instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#arguments.instanceOperationUid#/>
</cfquery>
<cfelse>
<cfreturn representationOf(this.helper.formatMessage(
"There is a started operation on this instance",
"Concurrent operations are not supported (job status: #jobStatus#)")
).withStatus(422)/>
</cfif>
</cfloop>
<cfquery name="local.qCheckCfsParams" result="local.result">
select sop.svc_operation_cfs_param_id, sop.svc_operation_cfs_param, sop.is_required,
iop.instance_operation_cfs_param_uid::text as instance_operation_cfs_param_uid, iop.param_value
from svc_operation_cfs_param sop
left outer join instance_operation_cfs_param iop on (sop.svc_operation_cfs_param_id=iop.svc_operation_cfs_param_id AND iop.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#" null=#!isValid('guid',arguments.instanceOperationUid)#/>)
where sop.svc_operation_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#local.qSvcOperation.svc_operation_id#"/>
</cfquery>
<cfset local.cfsParamChecker = CreateObject("component", "instance_operation_cfs_param_ls")/>
<cfloop query=#local.qCheckCfsParams#>
<cfif (local.qCheckCfsParams.is_required GT 0 AND NOT len(local.qCheckCfsParams.instance_operation_cfs_param_uid) GT 0)>
<cfreturn representationOf(this.helper.formatMessage("required CFS parameter #local.qCheckCfsParams.svc_operation_cfs_param# (#local.qCheckCfsParams.svc_operation_cfs_param_id#) is missing", "Missing required CFS parameter")).withStatus(422)/>
<cfelse>
<cfif isValid("guid",qCheckCfsParams.instance_operation_cfs_param_uid)>
<cfset local.cfsParamChecker.checkParam(local.qCheckCfsParams.svc_operation_cfs_param_id, qCheckCfsParams.param_value, arguments.usrId, qCheckCfsParams.instance_operation_cfs_param_uid)/>
<cfelse>
<cfset local.cfsParamChecker.checkParam(local.qCheckCfsParams.svc_operation_cfs_param_id, qCheckCfsParams.param_value, arguments.usrId)/>
</cfif>
</cfif>
</cfloop>
<cfset checkCfsResourceRealmAccess(arguments.instanceOperationUid)/>
<cfset var validationMessage = createObject("component","instance_operation").validateCfsParams(arguments.instanceOperationUid)/>
<cfif len(validationMessage)>
<cfthrow type="inconsistentCfsParams" message="Some CFS parameters are incompatible" detail="#validationMessage#"/>
</cfif>
<cfset generateRfsParams(arguments.instanceOperationUid, arguments.usrId, arguments.contragentId, arguments.contractId)/>
<cfset checkRfsResourceRealmAccess(arguments.instanceOperationUid)/>
<cfset submitJob(arguments.instanceOperationUid)/>
<cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch>
<cfcatch type="inconsistentCfsParams">
<cfreturn representationOf(this.helper.formatException(cfcatch,'Inconsistent CFS parameters')).withStatus(422)/>
</cfcatch>
<cfcatch type="missingDependency">
<cfreturn representationOf(this.helper.formatException(cfcatch,"Missing Dependency")).withStatus(424)/>
</cfcatch>
</cftry>
<cfset generateRfsParams(arguments.instanceOperationUid, arguments.usrId, arguments.contragentId, arguments.contractId)/>
<cfreturn noData().withStatus(201, "Created") />
</cffunction>
<cffunction name="generateRfsParams">
<cfargument name="instanceOperationUid" type="guid"/>
<cfargument name="usrId" type="numeric"/>
<cfargument name="contragentId" type="numeric"/>
<cfargument name="contractId" type="numeric"/>
<cfquery name="qSvcOperation">
select so.svc_operation_id, io.instance_uid, so.operation, r.resource_realm, io.resource_realm_id
from instance_operation io
join instance e on (io.instance_uid=e.instance_uid)
join svc_operation so on (e.service_id=so.svc_id AND io.operation=so.operation)
left outer join resource_realm r on io.resource_realm_id=r.resource_realm_id
where io.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#arguments.instanceOperationUid# null=#!isValid("guid",arguments.instanceOperationUid)#/>
</cfquery>
<cfset setInstanceOperationRfsParam(arguments.instanceOperationUid, "instanceUid", qSvcOperation.instance_uid)/>
<cfset setInstanceOperationRfsParam(arguments.instanceOperationUid, "operationUid", arguments.instanceOperationUid)/>
<cfset setInstanceOperationRfsParam(arguments.instanceOperationUid, "modifierId", arguments.usrId)/>
<cfif qSvcOperation.operation EQ "create">
<cfset setInstanceOperationRfsParam(arguments.instanceOperationUid, "billingObject", "underconstruction")/>
<cfset setInstanceOperationRfsParam(arguments.instanceOperationUid, "contragentCode", getContragentCode(arguments.contragentId))/>
</cfif>
<cfquery name="qWriteRfsFromCfsParams">
insert into instance_operation_param (instance_operation_uid,param,param_value)
select
iocp.instance_operation_uid
,sop.svc_operation_param
,iocp.param_value
from instance_operation_cfs_param iocp
join svc_operation_cfs_param socp on (iocp.svc_operation_cfs_param_id=socp.svc_operation_cfs_param_id)
join svc_operation_param sop on (socp.svc_operation_id=sop.svc_operation_id AND socp.svc_operation_cfs_param=sop.svc_operation_param)
where iocp.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#"/>
ON CONFLICT (instance_operation_uid,param)
DO UPDATE SET param_value = EXCLUDED.param_value;
</cfquery>
<cfquery name="qWriteRfsParamsFromDefaults">
insert into instance_operation_param (instance_operation_uid,param,param_value)
select
<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#"/>
,sop.svc_operation_param
,sop.default_value
from svc_operation_param sop
where sop.svc_operation_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#qSvcOperation.svc_operation_id#"/> AND length(sop.default_value)>0
ON CONFLICT (instance_operation_uid,param)
DO NOTHING;
</cfquery>
</cffunction>
<cffunction name="submitJob">
<cfargument name="instanceOperationUid" type="string" required=true hint="type:guid"/>
<cfquery name="qInstanceOperation">
select so.url_prefix, so.url_suffix, o.operation, svc.version
from instance_operation o
join instance i on (o.instance_uid=i.instance_uid)
join svc on (i.service_id=svc.svc_id)
left outer join svc_operation so on (i.service_id=so.svc_id AND o.operation=so.operation)
where o.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#arguments.instanceOperationUid#/>
</cfquery>
<cfquery name="qState">
select s.instance_data->'job'->>'jobAppVersion' as jobAppVersion
from instance_operation o
join instance_state s on (o.instance_uid=s.instance_uid)
where o.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#arguments.instanceOperationUid#/>
order by s.version desc
limit 1
</cfquery>
<cfquery name="qInstanceOperationParam">
select iop.param, iop.param_value
from instance_operation_param iop
where iop.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#arguments.instanceOperationUid#/>
AND length(iop.param)>0
</cfquery>
<cfif len(qState.jobAppVersion)>
<cfset var submit_url="#qInstanceOperation.url_prefix##qState.jobAppVersion##qInstanceOperation.url_suffix#"/>
<cfelse>
<cfset var submit_url="#qInstanceOperation.url_prefix##qInstanceOperation.version##qInstanceOperation.url_suffix#"/>
</cfif>
<cfquery name="qMarkOperationStart">
update instance_operation
set dt_submit=<cfqueryparam cfsqltype="cf_sql_timestamp" value=#now()#/>
,dt_start=null, dt_finish=null, submit_result='0'
,url=<cfqueryparam cfsqltype="cf_sql_varchar" value="#submit_url#"/>
where instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#arguments.instanceOperationUid#/>
</cfquery>
<cftry>
<cfhttp method="post"
url="#submit_url#"
multipart=true
multipartType="form-data"
timeout="3"
charset="utf-8"
result="orchestrator"
>
<cfhttpparam type="HEADER" name="Authorization" value="#request.ORCHESTRATOR_AUTH#"/>
<cfhttpparam type="HEADER" name="Accept" value="application/json"/>
<cfhttpparam type="HEADER" name="User-Agent" value="#request.USER_AGENT#"/>
<cfhttpparam type="formfield" name="delay" value="0sec"/>
<cfhttpparam type="formfield" name="authHeader" value=#request.auth_header#/>
<cfloop query="qInstanceOperationParam">
<cfhttpparam type="formfield" name="#param#" value="#param_value#"/>
</cfloop>
</cfhttp>
<cfcatch type="any">
<cfthrow message="Cannot initiate connection to the orchestrator #cfcatch.message#" detail="#cfcatch.detail#"/>
</cfcatch>
</cftry>
<cfif len(orchestrator.errorDetail)>
<cfthrow type="missingDependency" message="Orchestrator communication error" detail="#orchestrator.errorDetail#"/>
</cfif>
<cfquery name="qMarkOperationSubmit">
update instance_operation
set submit_result=<cfqueryparam cfsqltype="cf_sql_varchar" value=#orchestrator.responseHeader.status_code#/>
where instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#arguments.instanceOperationUid#/>
</cfquery>
<cfset sleep(0)/>
<cfif listFind("200,201",#orchestrator.responseHeader.status_code#)>
<cftry>
<cfset var buildURL="#orchestrator.responseHeader.Location#/api/json"/>
<cfhttp method="get"
url="#buildUrl#"
timeout="3"
charset="utf-8"
result="job"
>
<cfhttpparam type="HEADER" name="Authorization" value="#request.ORCHESTRATOR_AUTH#">
<cfhttpparam type="HEADER" name="Accept" value="application/json">
</cfhttp>
<cfset var operation_url = ""/>
<cfif structKeyExists(job,"filecontent")>
<cfset var jobData=#deserializeJson(job.filecontent)#/>
<cfset operation_url=jobData.executable.url />
<cfquery name="qSetStatusUrl">
update instance_operation
set status_url=<cfqueryparam cfsqltype="cf_sql_varchar" value="#operation_url#api/json" null=#(operation_url EQ "")#/>
where instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#arguments.instanceOperationUid#/>
</cfquery>
</cfif>
<cfcatch type="any">
<cfrethrow/>
</cfcatch>
</cftry>
</cfif>
</cffunction>
<cffunction name="setInstanceOperationRfsParam">
<cfargument name="instanceOperationUid" type="guid"/>
<cfargument name="param"/>
<cfargument name="val"/>
<cfquery name="qSaveRfsParam">
insert into instance_operation_param (instance_operation_uid,param,param_value)
values (
<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#"/>
,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.param#"/>
,<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.val#"/>
)
ON CONFLICT (instance_operation_uid,param)
DO UPDATE SET param_value = EXCLUDED.param_value;
</cfquery>
</cffunction>
<cffunction name="getJobStatus">
<cfargument name="status_url">
<cftry>
<cfhttp method="get"
url="#arguments.status_url#"
timeout="3"
charset="utf-8"
result="local.jobStatus"
>
<cfhttpparam type="HEADER" name="Authorization" value="#request.ORCHESTRATOR_AUTH#">
<cfhttpparam type="HEADER" name="Accept" value="application/json">
</cfhttp>
<cftry>
<cfset var jobStatusData=#deserializeJson(local.jobStatus.filecontent)#/>
<cfreturn jobStatusData.result/>
<cfcatch type="any">
<cfreturn "cannot obtain job result"/>
</cfcatch>
</cftry>
<cfcatch type="any">
<cfthrow message="Cannot connect to the orchestrator. #cfcatch.message#" detail="#cfcatch.detail#"/>
</cfcatch>
</cftry>
</cffunction>
<cffunction name="getContragentCode">
<cfargument name="contragentId">
<cfquery name="qContragentCode">
select external_code
from contragent
where contragent_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.contragentId# null=#!isNumeric(arguments.contragentId)#/>
</cfquery>
<cfreturn #qContragentCode.external_code#/>
</cffunction>
<cffunction name="checkCfsResourceRealmAccess">
<cfargument name="instanceOperationUid" type="guid">
<cfset var local={}/>
<cfquery name="local.qParam">
select sop.svc_operation_cfs_param
from instance_operation io
join instance e on (io.instance_uid=e.instance_uid)
join svc_operation so on (e.service_id=so.svc_id AND io.operation=so.operation)
join svc_operation_cfs_param sop on (so.svc_operation_id=sop.svc_operation_id)
where io.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#" null=#!isValid("guid",arguments.instanceOperationUid)#/>
AND LOWER(sop.svc_operation_cfs_param)=LOWER('resourceRealm')
</cfquery>
<cfif local.qParam.recordCount EQ 0>
<cfreturn/>
</cfif>
<cfquery name="local.qOperation">
select io.operation
from instance_operation io
where io.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#" null=#!isValid("guid",arguments.instanceOperationUid)#/>
</cfquery>
<cfquery name="local.qContract">
select c.contract_id
from instance_operation io
join instance e on (io.instance_uid=e.instance_uid)
join specification_item si on (e.specification_item_id=si.specification_item_id)
join specification s on (si.specification_id=s.specification_id)
join contract c on (s.contract_id=c.contract_id)
where io.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#" null=#!isValid("guid",arguments.instanceOperationUid)#/>
</cfquery>
<cfquery name="local.qCheckResourceRealmAccess">
select r.resource_realm_id, r.resource_realm, sop.svc_operation_cfs_param, iop.param_value, a.contract_id, a.is_enabled
from instance_operation_cfs_param iop
join svc_operation_cfs_param sop on (iop.svc_operation_cfs_param_id=sop.svc_operation_cfs_param_id)
join resource_realm r on (sop.svc_operation_cfs_param='resourceRealm' AND iop.param_value=r.resource_realm)
join resource_realm_access a on (r.resource_realm_id=a.resource_realm_id)
where iop.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#" null=#!isValid("guid",arguments.instanceOperationUid)#/>
AND (a.contract_id=<cfqueryparam cfsqltype="CF_SQL_INTEGER" value=#local.qContract.contract_id# null=#!isValid("integer",local.qContract.contract_id)#/> OR a.contract_id=0)
AND a.is_enabled
</cfquery>
<cfif local.qCheckResourceRealmAccess.recordCount EQ 0>
<cfthrow message="resource realm specified in CFS params is not available for current contract" detail="CFS resource realm unawailable. Instance operation UID #arguments.instanceOperationUid#. Contract ID #local.qContract.contract_id#"/>
</cfif>
</cffunction>
<cffunction name="checkRfsResourceRealmAccess">
<cfargument name="instanceOperationUid" type="guid">
<cfset var local={}/>
<cfquery name="local.qParamRRExists">
select count(*) as cnt
from instance_operation_param iop
where iop.param='resourceRealm' AND
iop.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#" null=#!isValid("guid",arguments.instanceOperationUid)#/>
</cfquery>
<cfif local.qParamRRExists.cnt EQ 0>
<cfreturn/>
</cfif>
<cfquery name="local.qContract">
select c.contract_id
from instance_operation io
join instance e on (io.instance_uid=e.instance_uid)
join specification_item si on (e.specification_item_id=si.specification_item_id)
join specification s on (si.specification_id=s.specification_id)
join contract c on (s.contract_id=c.contract_id)
where io.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#" null=#!isValid("guid",arguments.instanceOperationUid)#/>
</cfquery>
<cfquery name="local.qCheckResourceRealmAccess">
select r.resource_realm_id, r.resource_realm, iop.param, iop.param_value, a.contract_id, a.is_enabled
from resource_realm r
join resource_realm_access a on (r.resource_realm_id=a.resource_realm_id)
join instance_operation_param iop on (r.resource_realm=iop.param_value AND iop.param='resourceRealm')
where iop.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#" null=#!isValid("guid",arguments.instanceOperationUid)#/>
AND (a.contract_id=<cfqueryparam cfsqltype="CF_SQL_INTEGER" value=#local.qContract.contract_id# null=#!isValid("integer",local.qContract.contract_id)#/> OR a.contract_id=0)
AND a.is_enabled
</cfquery>
<cfif local.qCheckResourceRealmAccess.recordCount EQ 0>
<cfthrow message="resource realm specified in RFS params is not available for current contract" detail="RFS resource realm unawailable. Instance operation UID #arguments.instanceOperationUid#. Contract ID #local.qContract.contract_id#"/>
</cfif>
</cffunction>
</cfcomponent>