diff --git a/api/src/main/java/com/epam/pipeline/dao/pipeline/PipelineRunDao.java b/api/src/main/java/com/epam/pipeline/dao/pipeline/PipelineRunDao.java index 852331b4cd..05034445a8 100644 --- a/api/src/main/java/com/epam/pipeline/dao/pipeline/PipelineRunDao.java +++ b/api/src/main/java/com/epam/pipeline/dao/pipeline/PipelineRunDao.java @@ -1103,7 +1103,8 @@ public enum PipelineRunParameters { KUBE_SERVICE_ENABLED, CLUSTER_PRICE, NODE_POOL_ID, - NODE_START_DATE; + NODE_START_DATE, + PROJECT_ID; public static final RunAccessType DEFAULT_ACCESS_TYPE = RunAccessType.ENDPOINT; @@ -1115,6 +1116,7 @@ static MapSqlParameterSource getParameters(PipelineRun run, Connection connectio params.addValue(VERSION.name(), run.getVersion()); params.addValue(START_DATE.name(), run.getStartDate()); params.addValue(NODE_START_DATE.name(), run.getInstanceStartDate()); + params.addValue(PROJECT_ID.name(), run.getProjectId()); params.addValue(END_DATE.name(), run.getEndDate()); params.addValue(PARAMETERS.name(), run.getParams()); params.addValue(STATUS.name(), run.getStatus().getId()); @@ -1250,6 +1252,7 @@ public static PipelineRun parsePipelineRun(ResultSet rs) throws SQLException { run.setActualCmd(rs.getString(ACTUAL_CMD.name())); run.setSensitive(rs.getBoolean(SENSITIVE.name())); run.setKubeServiceEnabled(rs.getBoolean(KUBE_SERVICE_ENABLED.name())); + run.setProjectId(rs.getLong(PROJECT_ID.name())); RunInstance instance = new RunInstance(); instance.setNodeDisk(rs.getInt(NODE_DISK.name())); instance.setEffectiveNodeDisk(rs.getInt(NODE_REAL_DISK.name())); diff --git a/api/src/main/java/com/epam/pipeline/manager/pipeline/PipelineRunManager.java b/api/src/main/java/com/epam/pipeline/manager/pipeline/PipelineRunManager.java index bb73ac89d5..edd99f165b 100644 --- a/api/src/main/java/com/epam/pipeline/manager/pipeline/PipelineRunManager.java +++ b/api/src/main/java/com/epam/pipeline/manager/pipeline/PipelineRunManager.java @@ -40,6 +40,7 @@ import com.epam.pipeline.entity.contextual.ContextualPreferenceLevel; import com.epam.pipeline.entity.datastorage.AbstractDataStorage; import com.epam.pipeline.entity.docker.ToolVersion; +import com.epam.pipeline.entity.metadata.FolderWithMetadata; import com.epam.pipeline.entity.metadata.MetadataEntity; import com.epam.pipeline.entity.metadata.PipeConfValue; import com.epam.pipeline.entity.metadata.PipeConfValueType; @@ -452,6 +453,7 @@ public PipelineRun launchPipeline(final PipelineConfiguration configuration, fin } run.parseParameters(); updateMetadataEntities(run); + run.setProjectId(getPipelineProjectId(pipeline)); return run; } @@ -1922,4 +1924,12 @@ private void tryRemoveInstanceTags(final PipelineRun run) { log.error("An error occurred during cloud resource tags removal for run '{}'", run.getId(), e); } } + + private Long getPipelineProjectId(final Pipeline pipeline) { + if (pipeline == null || pipeline.getId() == null) { + return null; + } + final FolderWithMetadata project = folderApiService.getProject(pipeline.getId(), AclClass.PIPELINE); + return project != null ? project.getId() : null; + } } diff --git a/api/src/main/resources/dao/filter-dao.xml b/api/src/main/resources/dao/filter-dao.xml index 884b9142dd..edd4bddf49 100644 --- a/api/src/main/resources/dao/filter-dao.xml +++ b/api/src/main/resources/dao/filter-dao.xml @@ -77,7 +77,8 @@ r.pipeline_name, r.cluster_price, r.node_pool_id, - r.node_start_date + r.node_start_date, + r.project_id FROM pipeline.pipeline_run r WHERE @WHERE@ diff --git a/api/src/main/resources/dao/pipeline-run-dao.xml b/api/src/main/resources/dao/pipeline-run-dao.xml index 589f97f063..386cccf4fd 100644 --- a/api/src/main/resources/dao/pipeline-run-dao.xml +++ b/api/src/main/resources/dao/pipeline-run-dao.xml @@ -75,7 +75,8 @@ tags, sensitive, pipeline_name, - node_start_date) + node_start_date, + project_id) VALUES ( :RUN_ID, :PIPELINE_ID, @@ -128,7 +129,8 @@ to_jsonb(:TAGS::jsonb), :SENSITIVE, :PIPELINE_NAME, - :NODE_START_DATE) + :NODE_START_DATE, + :PROJECT_ID) ]]> @@ -191,6 +193,7 @@ r.pipeline_name, r.node_pool_id, r.node_start_date, + r.project_id, CASE WHEN EXISTS ( SELECT 1 FROM pipeline.pipeline_run_log init_tasks @@ -287,7 +290,8 @@ pipeline_name, cluster_price, node_pool_id, - node_start_date + node_start_date, + project_id FROM pipeline.pipeline_run WHERE @@ -355,7 +359,8 @@ pipeline_name, cluster_price, node_pool_id, - node_start_date + node_start_date, + project_id FROM pipeline.pipeline_run WHERE @@ -423,7 +428,8 @@ pipeline_name, cluster_price, node_pool_id, - node_start_date + node_start_date, + project_id FROM pipeline.pipeline_run WHERE @@ -557,7 +563,8 @@ sensitive = :SENSITIVE, kube_service_enabled = :KUBE_SERVICE_ENABLED, pipeline_name = :PIPELINE_NAME, - node_start_date = :NODE_START_DATE + node_start_date = :NODE_START_DATE, + project_id = :PROJECT_ID WHERE run_id = :RUN_ID ]]> @@ -667,7 +674,8 @@ r.pipeline_name, r.cluster_price, r.node_pool_id, - r.node_start_date + r.node_start_date, + r.project_id FROM pipeline.pipeline_run r WHERE @@ -737,7 +745,8 @@ r.pipeline_name, r.cluster_price, r.node_pool_id, - r.node_start_date + r.node_start_date, + r.project_id FROM pipeline.pipeline_run r WHERE @@ -805,6 +814,7 @@ r.cluster_price, r.node_pool_id, r.node_start_date, + r.project_id, CASE WHEN EXISTS ( SELECT 1 FROM pipeline.pipeline_run_service_url su @@ -873,6 +883,7 @@ active_run.cluster_price, active_run.node_pool_id, active_run.node_start_date, + active_run.project_id, CASE WHEN EXISTS ( SELECT 1 FROM pipeline.pipeline_run_service_url su @@ -1095,7 +1106,8 @@ r.pipeline_name, r.cluster_price, r.node_pool_id, - r.node_start_date + r.node_start_date, + r.project_id FROM pipeline.pipeline_run r WHERE @@ -1161,7 +1173,8 @@ r.pipeline_name, r.cluster_price, r.node_pool_id, - r.node_start_date + r.node_start_date, + r.project_id FROM pipeline.pipeline_run r WHERE @@ -1228,6 +1241,7 @@ r.cluster_price, r.node_pool_id, r.node_start_date, + r.project_id, CASE WHEN EXISTS ( SELECT 1 FROM pipeline.pipeline_run_log init_tasks @@ -1320,6 +1334,7 @@ runs.cluster_price, runs.node_pool_id, runs.node_start_date, + runs.project_id, CASE WHEN EXISTS ( SELECT 1 FROM pipeline.pipeline_run_log init_tasks @@ -1401,7 +1416,8 @@ p.pipeline_name, p.cluster_price, p.node_pool_id, - p.node_start_date + p.node_start_date, + p.project_id FROM (SELECT * FROM pipeline.pipeline_run r WHERE parent_id ISNULL @WHERE@ @@ -1463,7 +1479,8 @@ c.pipeline_name, c.cluster_price, c.node_pool_id, - c.node_start_date + c.node_start_date, + c.project_id FROM pipeline.pipeline_run c INNER JOIN runs ON runs.run_id = c.parent_id @@ -1523,6 +1540,7 @@ runs.cluster_price, runs.node_pool_id, runs.node_start_date, + runs.project_id, CASE WHEN EXISTS ( SELECT 1 FROM pipeline.pipeline_run_log init_tasks @@ -1602,6 +1620,7 @@ r.cluster_price, r.node_pool_id, r.node_start_date, + r.project_id, ( SELECT count(*) FROM pipeline.pipeline_run cr @@ -1776,7 +1795,8 @@ pipeline_name, cluster_price, node_pool_id, - node_start_date + node_start_date, + project_id FROM pipeline.pipeline_run r INNER JOIN (SELECT DISTINCT ON (run_id) run_id, status @@ -1848,7 +1868,8 @@ pipeline_name, cluster_price, node_pool_id, - node_start_date + node_start_date, + project_id FROM pipeline.pipeline_run r INNER JOIN (SELECT DISTINCT ON (run_id) run_id, status @@ -1915,7 +1936,8 @@ ar.pipeline_name, ar.cluster_price, ar.node_pool_id, - ar.node_start_date + ar.node_start_date, + null as project_id FROM pipeline.archive_run ar WHERE ar.end_date BETWEEN :PERIOD_START AND :PERIOD_END @@ -1990,7 +2012,8 @@ pipeline_name, cluster_price, node_pool_id, - node_start_date + node_start_date, + project_id FROM pipeline.pipeline_run WHERE @@ -2058,7 +2081,8 @@ pipeline_name, cluster_price, node_pool_id, - node_start_date + node_start_date, + project_id FROM pipeline.pipeline_run WHERE @@ -2126,7 +2150,8 @@ pipeline_name, cluster_price, node_pool_id, - node_start_date + node_start_date, + project_id FROM pipeline.pipeline_run WHERE @@ -2194,7 +2219,8 @@ pipeline_name, cluster_price, node_pool_id, - node_start_date + node_start_date, + project_id FROM pipeline.pipeline_run WHERE @@ -2272,7 +2298,8 @@ pipeline_name, cluster_price, node_pool_id, - node_start_date + node_start_date, + project_id FROM pipeline.pipeline_run WHERE @@ -2340,7 +2367,8 @@ pipeline_name, cluster_price, node_pool_id, - node_start_date + node_start_date, + project_id FROM pipeline.pipeline_run WHERE @@ -2451,7 +2479,8 @@ pipeline_name, cluster_price, node_pool_id, - node_start_date + node_start_date, + project_id FROM pipeline.pipeline_run WHERE parent_id ISNULL AND status IN (:list) AND ( @WHERE@ ) diff --git a/api/src/main/resources/db/migration/v2025.01.28_19.00__issue_3866_project_id_for_pipeline_runs.sql b/api/src/main/resources/db/migration/v2025.01.28_19.00__issue_3866_project_id_for_pipeline_runs.sql new file mode 100644 index 0000000000..abe2240ebc --- /dev/null +++ b/api/src/main/resources/db/migration/v2025.01.28_19.00__issue_3866_project_id_for_pipeline_runs.sql @@ -0,0 +1 @@ +ALTER TABLE pipeline.PIPELINE_RUN ADD COLUMN project_id BIGINT; \ No newline at end of file diff --git a/api/src/test/java/com/epam/pipeline/dao/pipeline/PipelineRunDaoTest.java b/api/src/test/java/com/epam/pipeline/dao/pipeline/PipelineRunDaoTest.java index 725afaee74..75966bd2d2 100644 --- a/api/src/test/java/com/epam/pipeline/dao/pipeline/PipelineRunDaoTest.java +++ b/api/src/test/java/com/epam/pipeline/dao/pipeline/PipelineRunDaoTest.java @@ -141,6 +141,7 @@ public class PipelineRunDaoTest extends AbstractJdbcTest { private static final String NODE_TYPE = "m5.xlarge"; private static final String NODE_TYPE_2 = "r5.2xlarge"; private static final String TRUE = "True"; + private static final long PROJECT_ID = 1L; private static final BigDecimal INITIAL_CLUSTER_PRICE_1 = BigDecimal.valueOf(1.9511111); private static final BigDecimal INITIAL_CLUSTER_PRICE_2 = BigDecimal.valueOf(123456.5666); @@ -211,6 +212,7 @@ public void testFilterPipelineRuns() throws WrongFilterException { List pipelineRuns = filterDao.filterPipelineRuns( FilterExpression.prepare(logicalExpression), 1, 2, 0); assertEquals(1, pipelineRuns.size()); + assertEquals(PROJECT_ID, pipelineRuns.get(0).getProjectId().longValue()); assertEquals(pipelineRuns.get(0).getPodId(), run1.getPodId()); } @@ -255,6 +257,7 @@ public void testLoadByIds() { createTestPipelineRun(); List pipelineRuns = pipelineRunDao.loadPipelineRuns(Collections.singletonList(run1.getId())); + assertEquals(PROJECT_ID, pipelineRuns.get(0).getProjectId().longValue()); assertEquals(1, pipelineRuns.size()); assertEquals(run1.getId(), pipelineRuns.get(0).getId()); } @@ -1427,6 +1430,7 @@ private PipelineRun buildPipelineRun(final Long pipelineId, final Date start, fi run.setParams(TEST_PARAMS); run.setOwner(USER); run.setPlatform(TEST_PLATFORM); + run.setProjectId(PROJECT_ID); Map systemParams = EnvVarsBuilderTest.matchSystemParams(); PipelineConfiguration configuration = EnvVarsBuilderTest.matchPipeConfig(); diff --git a/api/src/test/java/com/epam/pipeline/manager/pipeline/PipelineRunManagerLaunchTest.java b/api/src/test/java/com/epam/pipeline/manager/pipeline/PipelineRunManagerLaunchTest.java index 6941c1aad6..f4bb729394 100644 --- a/api/src/test/java/com/epam/pipeline/manager/pipeline/PipelineRunManagerLaunchTest.java +++ b/api/src/test/java/com/epam/pipeline/manager/pipeline/PipelineRunManagerLaunchTest.java @@ -16,6 +16,7 @@ package com.epam.pipeline.manager.pipeline; +import com.epam.pipeline.acl.folder.FolderApiService; import com.epam.pipeline.common.MessageHelper; import com.epam.pipeline.dao.pipeline.PipelineRunDao; import com.epam.pipeline.entity.BaseEntity; @@ -24,6 +25,7 @@ import com.epam.pipeline.entity.configuration.PipeConfValueVO; import com.epam.pipeline.entity.configuration.PipelineConfiguration; import com.epam.pipeline.entity.contextual.ContextualPreferenceExternalResource; +import com.epam.pipeline.entity.metadata.FolderWithMetadata; import com.epam.pipeline.entity.notification.NotificationType; import com.epam.pipeline.entity.pipeline.Pipeline; import com.epam.pipeline.entity.pipeline.PipelineRun; @@ -32,6 +34,7 @@ import com.epam.pipeline.entity.pipeline.run.PipelineStartNotificationRequest; import com.epam.pipeline.entity.pipeline.run.RunStatus; import com.epam.pipeline.entity.region.AwsRegion; +import com.epam.pipeline.entity.security.acl.AclClass; import com.epam.pipeline.manager.cluster.InstanceOfferManager; import com.epam.pipeline.manager.datastorage.DataStorageManager; import com.epam.pipeline.manager.docker.ToolVersionManager; @@ -81,6 +84,7 @@ import static java.util.stream.Collectors.toMap; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; @@ -121,6 +125,8 @@ public class PipelineRunManagerLaunchTest { TEST_PERIOD.plusHours(HOURS_18)); private static final RunStatus TEST_STATUS_3 = new RunStatus(ID_2, TaskStatus.RUNNING, null, TEST_PERIOD.plusHours(HOURS_18)); + private static final long PIPELINE_ID = 1L; + private static final long FOLDER_ID = 1L; @InjectMocks private final PipelineRunManager pipelineRunManager = new PipelineRunManager(); @@ -173,6 +179,9 @@ public class PipelineRunManagerLaunchTest { @Mock private ContextualNotificationRegistrationManager contextualNotificationRegistrationManager; + @Mock + private FolderApiService folderApiService; + private final Tool tool = getTool(IMAGE, DEFAULT_COMMAND); private final AwsRegion defaultAwsRegion = getDefaultAwsRegion(ID); private final AwsRegion nonAllowedAwsRegion = getNonDefaultAwsRegion(ID_2); @@ -271,6 +280,23 @@ public void launchPipelineShouldValidatePipelineInstanceType() { eq(defaultRegionResources), eq(REGION_ID), eq(true)); } + @Test + public void launchPipelineFromProjectShouldSetUpProjectId() { + final FolderWithMetadata folder = new FolderWithMetadata(); + final Pipeline pipeline = new Pipeline(PIPELINE_ID); + folder.setId(FOLDER_ID); + doReturn(folder).when(folderApiService).getProject(PIPELINE_ID, AclClass.PIPELINE); + final PipelineRun run = launchPipeline(configuration, pipeline, null, null, null); + assertEquals(FOLDER_ID, run.getProjectId().longValue()); + } + + @Test + public void launchPipelineWithoutProjectShouldSetProjectIdAsNull() { + doReturn(null).when(folderApiService).getProject(PIPELINE_ID, AclClass.PIPELINE); + final PipelineRun run = launchPipeline(configuration, new Pipeline(PIPELINE_ID), null, null, null); + assertNull(run.getProjectId()); + } + @Test public void launchPipelineShouldValidatePipelineInstanceTypeInTheSpecifiedRegion() { configuration.setCloudRegionId(NON_ALLOWED_REGION_ID); diff --git a/api/src/test/java/com/epam/pipeline/util/TestUtils.java b/api/src/test/java/com/epam/pipeline/util/TestUtils.java index 5a8cf12314..15e32916dc 100644 --- a/api/src/test/java/com/epam/pipeline/util/TestUtils.java +++ b/api/src/test/java/com/epam/pipeline/util/TestUtils.java @@ -58,6 +58,7 @@ public final class TestUtils { public static final String DEFAULT_STORAGE_NAME_PATTERN = "@@-home"; public static final String TEMPLATE_REPLACE_MARK = "@@"; public static final String TEST_PLATFORM = "linux"; + private static final long PROJECT_ID = 1L; private TestUtils() { // no op @@ -152,6 +153,7 @@ public static PipelineRun createPipelineRun(Long pipelineId, String params, Task run.setParentRunId(parentRunId); run.setRunSids(runSids); run.setPlatform(TEST_PLATFORM); + run.setProjectId(PROJECT_ID); RunInstance instance = new RunInstance(); instance.setCloudRegionId(regionId); diff --git a/core/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java b/core/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java index 1b8387b72a..c62116afcb 100644 --- a/core/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java +++ b/core/src/main/java/com/epam/pipeline/entity/pipeline/PipelineRun.java @@ -128,6 +128,7 @@ public class PipelineRun extends AbstractSecuredEntity { private List restartedRuns; private List runStatuses; private boolean nonPause; + private Long projectId; /** * For CMD runs parent is TOOL, for usual runs - it is a PIPELINE