mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-24 23:34:51 +00:00
Initial JSONSchema specification for Asset Certification (#18392)
* Initial JSONSchema specification for Asset Certification * Add backend logic to updateCertification * Add Tests for Asset Certification * Update certification config and set defaults * Fix Checkstyle * Fix Tests * Fix checkstyle
This commit is contained in:
parent
289404748a
commit
57c22b5fbe
@ -122,6 +122,7 @@ public final class Entity {
|
|||||||
public static final String FIELD_STYLE = "style";
|
public static final String FIELD_STYLE = "style";
|
||||||
|
|
||||||
public static final String FIELD_LIFE_CYCLE = "lifeCycle";
|
public static final String FIELD_LIFE_CYCLE = "lifeCycle";
|
||||||
|
public static final String FIELD_CERTIFICATION = "certification";
|
||||||
|
|
||||||
public static final String FIELD_DISABLED = "disabled";
|
public static final String FIELD_DISABLED = "disabled";
|
||||||
|
|
||||||
|
|||||||
@ -65,6 +65,7 @@ import org.openmetadata.schema.auth.PasswordResetToken;
|
|||||||
import org.openmetadata.schema.auth.PersonalAccessToken;
|
import org.openmetadata.schema.auth.PersonalAccessToken;
|
||||||
import org.openmetadata.schema.auth.RefreshToken;
|
import org.openmetadata.schema.auth.RefreshToken;
|
||||||
import org.openmetadata.schema.auth.TokenType;
|
import org.openmetadata.schema.auth.TokenType;
|
||||||
|
import org.openmetadata.schema.configuration.AssetCertificationSettings;
|
||||||
import org.openmetadata.schema.dataInsight.DataInsightChart;
|
import org.openmetadata.schema.dataInsight.DataInsightChart;
|
||||||
import org.openmetadata.schema.dataInsight.custom.DataInsightCustomChart;
|
import org.openmetadata.schema.dataInsight.custom.DataInsightCustomChart;
|
||||||
import org.openmetadata.schema.dataInsight.kpi.Kpi;
|
import org.openmetadata.schema.dataInsight.kpi.Kpi;
|
||||||
@ -4910,6 +4911,8 @@ public interface CollectionDAO {
|
|||||||
.readValue(json, String.class);
|
.readValue(json, String.class);
|
||||||
case PROFILER_CONFIGURATION -> JsonUtils.readValue(json, ProfilerConfiguration.class);
|
case PROFILER_CONFIGURATION -> JsonUtils.readValue(json, ProfilerConfiguration.class);
|
||||||
case SEARCH_SETTINGS -> JsonUtils.readValue(json, SearchSettings.class);
|
case SEARCH_SETTINGS -> JsonUtils.readValue(json, SearchSettings.class);
|
||||||
|
case ASSET_CERTIFICATION_SETTINGS -> JsonUtils.readValue(
|
||||||
|
json, AssetCertificationSettings.class);
|
||||||
default -> throw new IllegalArgumentException("Invalid Settings Type " + configType);
|
default -> throw new IllegalArgumentException("Invalid Settings Type " + configType);
|
||||||
};
|
};
|
||||||
settings.setConfigValue(value);
|
settings.setConfigValue(value);
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import static org.openmetadata.schema.utils.EntityInterfaceUtil.quoteName;
|
|||||||
import static org.openmetadata.service.Entity.ADMIN_USER_NAME;
|
import static org.openmetadata.service.Entity.ADMIN_USER_NAME;
|
||||||
import static org.openmetadata.service.Entity.DATA_PRODUCT;
|
import static org.openmetadata.service.Entity.DATA_PRODUCT;
|
||||||
import static org.openmetadata.service.Entity.DOMAIN;
|
import static org.openmetadata.service.Entity.DOMAIN;
|
||||||
|
import static org.openmetadata.service.Entity.FIELD_CERTIFICATION;
|
||||||
import static org.openmetadata.service.Entity.FIELD_CHILDREN;
|
import static org.openmetadata.service.Entity.FIELD_CHILDREN;
|
||||||
import static org.openmetadata.service.Entity.FIELD_DATA_PRODUCTS;
|
import static org.openmetadata.service.Entity.FIELD_DATA_PRODUCTS;
|
||||||
import static org.openmetadata.service.Entity.FIELD_DELETED;
|
import static org.openmetadata.service.Entity.FIELD_DELETED;
|
||||||
@ -78,8 +79,11 @@ import com.networknt.schema.JsonSchema;
|
|||||||
import com.networknt.schema.ValidationMessage;
|
import com.networknt.schema.ValidationMessage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.time.Instant;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
|
import java.time.Period;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.format.DateTimeParseException;
|
import java.time.format.DateTimeParseException;
|
||||||
import java.time.temporal.TemporalAccessor;
|
import java.time.temporal.TemporalAccessor;
|
||||||
@ -121,12 +125,14 @@ import org.openmetadata.schema.api.VoteRequest;
|
|||||||
import org.openmetadata.schema.api.VoteRequest.VoteType;
|
import org.openmetadata.schema.api.VoteRequest.VoteType;
|
||||||
import org.openmetadata.schema.api.feed.ResolveTask;
|
import org.openmetadata.schema.api.feed.ResolveTask;
|
||||||
import org.openmetadata.schema.api.teams.CreateTeam;
|
import org.openmetadata.schema.api.teams.CreateTeam;
|
||||||
|
import org.openmetadata.schema.configuration.AssetCertificationSettings;
|
||||||
import org.openmetadata.schema.entity.data.Table;
|
import org.openmetadata.schema.entity.data.Table;
|
||||||
import org.openmetadata.schema.entity.feed.Suggestion;
|
import org.openmetadata.schema.entity.feed.Suggestion;
|
||||||
import org.openmetadata.schema.entity.teams.Team;
|
import org.openmetadata.schema.entity.teams.Team;
|
||||||
import org.openmetadata.schema.entity.teams.User;
|
import org.openmetadata.schema.entity.teams.User;
|
||||||
import org.openmetadata.schema.system.EntityError;
|
import org.openmetadata.schema.system.EntityError;
|
||||||
import org.openmetadata.schema.type.ApiStatus;
|
import org.openmetadata.schema.type.ApiStatus;
|
||||||
|
import org.openmetadata.schema.type.AssetCertification;
|
||||||
import org.openmetadata.schema.type.ChangeDescription;
|
import org.openmetadata.schema.type.ChangeDescription;
|
||||||
import org.openmetadata.schema.type.ChangeEvent;
|
import org.openmetadata.schema.type.ChangeEvent;
|
||||||
import org.openmetadata.schema.type.Column;
|
import org.openmetadata.schema.type.Column;
|
||||||
@ -235,6 +241,7 @@ public abstract class EntityRepository<T extends EntityInterface> {
|
|||||||
@Getter protected final boolean supportsOwners;
|
@Getter protected final boolean supportsOwners;
|
||||||
@Getter protected final boolean supportsStyle;
|
@Getter protected final boolean supportsStyle;
|
||||||
@Getter protected final boolean supportsLifeCycle;
|
@Getter protected final boolean supportsLifeCycle;
|
||||||
|
@Getter protected final boolean supportsCertification;
|
||||||
protected final boolean supportsFollower;
|
protected final boolean supportsFollower;
|
||||||
protected final boolean supportsExtension;
|
protected final boolean supportsExtension;
|
||||||
protected final boolean supportsVotes;
|
protected final boolean supportsVotes;
|
||||||
@ -328,6 +335,11 @@ public abstract class EntityRepository<T extends EntityInterface> {
|
|||||||
this.patchFields.addField(allowedFields, FIELD_LIFE_CYCLE);
|
this.patchFields.addField(allowedFields, FIELD_LIFE_CYCLE);
|
||||||
this.putFields.addField(allowedFields, FIELD_LIFE_CYCLE);
|
this.putFields.addField(allowedFields, FIELD_LIFE_CYCLE);
|
||||||
}
|
}
|
||||||
|
this.supportsCertification = allowedFields.contains(FIELD_CERTIFICATION);
|
||||||
|
if (supportsCertification) {
|
||||||
|
this.patchFields.addField(allowedFields, FIELD_CERTIFICATION);
|
||||||
|
this.putFields.addField(allowedFields, FIELD_CERTIFICATION);
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, Pair<Boolean, BiConsumer<List<T>, Fields>>> fieldSupportMap = new HashMap<>();
|
Map<String, Pair<Boolean, BiConsumer<List<T>, Fields>>> fieldSupportMap = new HashMap<>();
|
||||||
|
|
||||||
@ -2627,6 +2639,7 @@ public abstract class EntityRepository<T extends EntityInterface> {
|
|||||||
updateReviewers();
|
updateReviewers();
|
||||||
updateStyle();
|
updateStyle();
|
||||||
updateLifeCycle();
|
updateLifeCycle();
|
||||||
|
updateCertification();
|
||||||
entitySpecificUpdate();
|
entitySpecificUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2929,6 +2942,53 @@ public abstract class EntityRepository<T extends EntityInterface> {
|
|||||||
recordChange(FIELD_LIFE_CYCLE, origLifeCycle, updatedLifeCycle, true);
|
recordChange(FIELD_LIFE_CYCLE, origLifeCycle, updatedLifeCycle, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateCertification() {
|
||||||
|
if (!supportsCertification) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AssetCertification origCertification = original.getCertification();
|
||||||
|
AssetCertification updatedCertification = updated.getCertification();
|
||||||
|
|
||||||
|
if (origCertification == updatedCertification || updatedCertification == null) return;
|
||||||
|
|
||||||
|
SystemRepository systemRepository = Entity.getSystemRepository();
|
||||||
|
AssetCertificationSettings assetCertificationSettings =
|
||||||
|
systemRepository.getAssetCertificationSettings();
|
||||||
|
|
||||||
|
String certificationLabel = updatedCertification.getTagLabel().getTagFQN();
|
||||||
|
|
||||||
|
validateCertification(certificationLabel, assetCertificationSettings);
|
||||||
|
|
||||||
|
long certificationDate = System.currentTimeMillis();
|
||||||
|
updatedCertification.setAppliedDate(certificationDate);
|
||||||
|
|
||||||
|
LocalDateTime nowDateTime =
|
||||||
|
LocalDateTime.ofInstant(Instant.ofEpochMilli(certificationDate), ZoneOffset.UTC);
|
||||||
|
Period datePeriod = Period.parse(assetCertificationSettings.getValidityPeriod());
|
||||||
|
LocalDateTime targetDateTime = nowDateTime.plus(datePeriod);
|
||||||
|
updatedCertification.setExpiryDate(targetDateTime.toInstant(ZoneOffset.UTC).toEpochMilli());
|
||||||
|
|
||||||
|
recordChange(FIELD_CERTIFICATION, origCertification, updatedCertification, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateCertification(
|
||||||
|
String certificationLabel, AssetCertificationSettings assetCertificationSettings) {
|
||||||
|
if (Optional.ofNullable(assetCertificationSettings).isEmpty()) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Certification is not configured. Please configure the Classification used for Certification in the Settings.");
|
||||||
|
} else {
|
||||||
|
String allowedClassification = assetCertificationSettings.getAllowedClassification();
|
||||||
|
String[] fqnParts = FullyQualifiedName.split(certificationLabel);
|
||||||
|
String parentFqn = FullyQualifiedName.getParentFQN(fqnParts);
|
||||||
|
if (!allowedClassification.equals(parentFqn)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"Invalid Classification: %s is not valid for Certification.",
|
||||||
|
certificationLabel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final boolean updateVersion(Double oldVersion) {
|
public final boolean updateVersion(Double oldVersion) {
|
||||||
Double newVersion = oldVersion;
|
Double newVersion = oldVersion;
|
||||||
if (majorVersionChange) {
|
if (majorVersionChange) {
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import com.slack.api.bolt.model.builtin.DefaultInstaller;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import javax.json.JsonPatch;
|
import javax.json.JsonPatch;
|
||||||
import javax.json.JsonValue;
|
import javax.json.JsonValue;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
@ -16,6 +17,7 @@ import lombok.SneakyThrows;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jdbi.v3.sqlobject.transaction.Transaction;
|
import org.jdbi.v3.sqlobject.transaction.Transaction;
|
||||||
import org.openmetadata.api.configuration.UiThemePreference;
|
import org.openmetadata.api.configuration.UiThemePreference;
|
||||||
|
import org.openmetadata.schema.configuration.AssetCertificationSettings;
|
||||||
import org.openmetadata.schema.email.SmtpSettings;
|
import org.openmetadata.schema.email.SmtpSettings;
|
||||||
import org.openmetadata.schema.entity.services.ingestionPipelines.PipelineServiceClientResponse;
|
import org.openmetadata.schema.entity.services.ingestionPipelines.PipelineServiceClientResponse;
|
||||||
import org.openmetadata.schema.security.client.OpenMetadataJWTClientConfig;
|
import org.openmetadata.schema.security.client.OpenMetadataJWTClientConfig;
|
||||||
@ -110,6 +112,15 @@ public class SystemRepository {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AssetCertificationSettings getAssetCertificationSettings() {
|
||||||
|
Optional<Settings> oAssetCertificationSettings =
|
||||||
|
Optional.ofNullable(getConfigWithKey(SettingsType.ASSET_CERTIFICATION_SETTINGS.value()));
|
||||||
|
|
||||||
|
return oAssetCertificationSettings
|
||||||
|
.map(settings -> (AssetCertificationSettings) settings.getConfigValue())
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
public Settings getEmailConfigInternal() {
|
public Settings getEmailConfigInternal() {
|
||||||
try {
|
try {
|
||||||
Settings setting = dao.getConfigWithKey(SettingsType.EMAIL_CONFIGURATION.value());
|
Settings setting = dao.getConfigWithKey(SettingsType.EMAIL_CONFIGURATION.value());
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
package org.openmetadata.service.resources.settings;
|
package org.openmetadata.service.resources.settings;
|
||||||
|
|
||||||
|
import static org.openmetadata.schema.settings.SettingsType.ASSET_CERTIFICATION_SETTINGS;
|
||||||
import static org.openmetadata.schema.settings.SettingsType.CUSTOM_UI_THEME_PREFERENCE;
|
import static org.openmetadata.schema.settings.SettingsType.CUSTOM_UI_THEME_PREFERENCE;
|
||||||
import static org.openmetadata.schema.settings.SettingsType.EMAIL_CONFIGURATION;
|
import static org.openmetadata.schema.settings.SettingsType.EMAIL_CONFIGURATION;
|
||||||
import static org.openmetadata.schema.settings.SettingsType.LOGIN_CONFIGURATION;
|
import static org.openmetadata.schema.settings.SettingsType.LOGIN_CONFIGURATION;
|
||||||
@ -30,6 +31,7 @@ import org.openmetadata.api.configuration.ThemeConfiguration;
|
|||||||
import org.openmetadata.api.configuration.UiThemePreference;
|
import org.openmetadata.api.configuration.UiThemePreference;
|
||||||
import org.openmetadata.schema.api.configuration.LoginConfiguration;
|
import org.openmetadata.schema.api.configuration.LoginConfiguration;
|
||||||
import org.openmetadata.schema.api.searcg.SearchSettings;
|
import org.openmetadata.schema.api.searcg.SearchSettings;
|
||||||
|
import org.openmetadata.schema.configuration.AssetCertificationSettings;
|
||||||
import org.openmetadata.schema.email.SmtpSettings;
|
import org.openmetadata.schema.email.SmtpSettings;
|
||||||
import org.openmetadata.schema.settings.Settings;
|
import org.openmetadata.schema.settings.Settings;
|
||||||
import org.openmetadata.schema.settings.SettingsType;
|
import org.openmetadata.schema.settings.SettingsType;
|
||||||
@ -124,6 +126,20 @@ public class SettingsCache {
|
|||||||
.withConfigValue(new SearchSettings().withEnableAccessControl(false));
|
.withConfigValue(new SearchSettings().withEnableAccessControl(false));
|
||||||
systemRepository.createNewSetting(setting);
|
systemRepository.createNewSetting(setting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialise Certification Settings
|
||||||
|
Settings certificationSettings =
|
||||||
|
systemRepository.getConfigWithKey(ASSET_CERTIFICATION_SETTINGS.toString());
|
||||||
|
if (certificationSettings == null) {
|
||||||
|
Settings setting =
|
||||||
|
new Settings()
|
||||||
|
.withConfigType(ASSET_CERTIFICATION_SETTINGS)
|
||||||
|
.withConfigValue(
|
||||||
|
new AssetCertificationSettings()
|
||||||
|
.withAllowedClassification("Certification")
|
||||||
|
.withValidityPeriod("P30D"));
|
||||||
|
systemRepository.createNewSetting(setting);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> T getSetting(SettingsType settingName, Class<T> clazz) {
|
public static <T> T getSetting(SettingsType settingName, Class<T> clazz) {
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"createClassification": {
|
||||||
|
"name": "Certification",
|
||||||
|
"description": "Certifying Data Asset will provide the users with a clear idea of how reliable a Data Asset is.",
|
||||||
|
"provider": "system",
|
||||||
|
"mutuallyExclusive": "true"
|
||||||
|
},
|
||||||
|
"createTags": [
|
||||||
|
{
|
||||||
|
"name": "Bronze",
|
||||||
|
"description": "Bronze certified Data Asset.",
|
||||||
|
"style": {
|
||||||
|
"color": "#CD7F32"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Silver",
|
||||||
|
"description": "Silver certified Data Asset.",
|
||||||
|
"style": {
|
||||||
|
"color": "#C0C0C0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Gold",
|
||||||
|
"description": "Gold certified Data Asset.",
|
||||||
|
"style": {
|
||||||
|
"color": "#FFD700"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -26,6 +26,7 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
import static org.openmetadata.common.utils.CommonUtil.listOf;
|
import static org.openmetadata.common.utils.CommonUtil.listOf;
|
||||||
import static org.openmetadata.common.utils.CommonUtil.listOrEmpty;
|
import static org.openmetadata.common.utils.CommonUtil.listOrEmpty;
|
||||||
import static org.openmetadata.common.utils.CommonUtil.nullOrEmpty;
|
import static org.openmetadata.common.utils.CommonUtil.nullOrEmpty;
|
||||||
@ -128,6 +129,7 @@ import org.openmetadata.schema.api.feed.CreateThread;
|
|||||||
import org.openmetadata.schema.api.teams.CreateTeam;
|
import org.openmetadata.schema.api.teams.CreateTeam;
|
||||||
import org.openmetadata.schema.api.teams.CreateTeam.TeamType;
|
import org.openmetadata.schema.api.teams.CreateTeam.TeamType;
|
||||||
import org.openmetadata.schema.api.tests.CreateTestSuite;
|
import org.openmetadata.schema.api.tests.CreateTestSuite;
|
||||||
|
import org.openmetadata.schema.configuration.AssetCertificationSettings;
|
||||||
import org.openmetadata.schema.dataInsight.DataInsightChart;
|
import org.openmetadata.schema.dataInsight.DataInsightChart;
|
||||||
import org.openmetadata.schema.dataInsight.type.KpiTarget;
|
import org.openmetadata.schema.dataInsight.type.KpiTarget;
|
||||||
import org.openmetadata.schema.entities.docStore.Document;
|
import org.openmetadata.schema.entities.docStore.Document;
|
||||||
@ -155,11 +157,14 @@ import org.openmetadata.schema.entity.teams.User;
|
|||||||
import org.openmetadata.schema.entity.type.Category;
|
import org.openmetadata.schema.entity.type.Category;
|
||||||
import org.openmetadata.schema.entity.type.CustomProperty;
|
import org.openmetadata.schema.entity.type.CustomProperty;
|
||||||
import org.openmetadata.schema.entity.type.Style;
|
import org.openmetadata.schema.entity.type.Style;
|
||||||
|
import org.openmetadata.schema.settings.Settings;
|
||||||
|
import org.openmetadata.schema.settings.SettingsType;
|
||||||
import org.openmetadata.schema.tests.TestDefinition;
|
import org.openmetadata.schema.tests.TestDefinition;
|
||||||
import org.openmetadata.schema.tests.TestSuite;
|
import org.openmetadata.schema.tests.TestSuite;
|
||||||
import org.openmetadata.schema.type.AccessDetails;
|
import org.openmetadata.schema.type.AccessDetails;
|
||||||
import org.openmetadata.schema.type.AnnouncementDetails;
|
import org.openmetadata.schema.type.AnnouncementDetails;
|
||||||
import org.openmetadata.schema.type.ApiStatus;
|
import org.openmetadata.schema.type.ApiStatus;
|
||||||
|
import org.openmetadata.schema.type.AssetCertification;
|
||||||
import org.openmetadata.schema.type.ChangeDescription;
|
import org.openmetadata.schema.type.ChangeDescription;
|
||||||
import org.openmetadata.schema.type.ChangeEvent;
|
import org.openmetadata.schema.type.ChangeEvent;
|
||||||
import org.openmetadata.schema.type.Column;
|
import org.openmetadata.schema.type.Column;
|
||||||
@ -178,6 +183,7 @@ import org.openmetadata.service.Entity;
|
|||||||
import org.openmetadata.service.OpenMetadataApplicationTest;
|
import org.openmetadata.service.OpenMetadataApplicationTest;
|
||||||
import org.openmetadata.service.exception.CatalogExceptionMessage;
|
import org.openmetadata.service.exception.CatalogExceptionMessage;
|
||||||
import org.openmetadata.service.jdbi3.EntityRepository.EntityUpdater;
|
import org.openmetadata.service.jdbi3.EntityRepository.EntityUpdater;
|
||||||
|
import org.openmetadata.service.jdbi3.SystemRepository;
|
||||||
import org.openmetadata.service.resources.apis.APICollectionResourceTest;
|
import org.openmetadata.service.resources.apis.APICollectionResourceTest;
|
||||||
import org.openmetadata.service.resources.bots.BotResourceTest;
|
import org.openmetadata.service.resources.bots.BotResourceTest;
|
||||||
import org.openmetadata.service.resources.databases.TableResourceTest;
|
import org.openmetadata.service.resources.databases.TableResourceTest;
|
||||||
@ -209,6 +215,7 @@ import org.openmetadata.service.resources.teams.*;
|
|||||||
import org.openmetadata.service.search.models.IndexMapping;
|
import org.openmetadata.service.search.models.IndexMapping;
|
||||||
import org.openmetadata.service.security.SecurityUtil;
|
import org.openmetadata.service.security.SecurityUtil;
|
||||||
import org.openmetadata.service.util.EntityUtil;
|
import org.openmetadata.service.util.EntityUtil;
|
||||||
|
import org.openmetadata.service.util.FullyQualifiedName;
|
||||||
import org.openmetadata.service.util.JsonUtils;
|
import org.openmetadata.service.util.JsonUtils;
|
||||||
import org.openmetadata.service.util.ResultList;
|
import org.openmetadata.service.util.ResultList;
|
||||||
import org.openmetadata.service.util.TestUtils;
|
import org.openmetadata.service.util.TestUtils;
|
||||||
@ -247,6 +254,7 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
|
|||||||
protected final boolean supportsDataProducts;
|
protected final boolean supportsDataProducts;
|
||||||
protected final boolean supportsExperts;
|
protected final boolean supportsExperts;
|
||||||
protected final boolean supportsReviewers;
|
protected final boolean supportsReviewers;
|
||||||
|
protected final boolean supportsCertification;
|
||||||
|
|
||||||
public static final String DATA_STEWARD_ROLE_NAME = "DataSteward";
|
public static final String DATA_STEWARD_ROLE_NAME = "DataSteward";
|
||||||
public static final String DATA_CONSUMER_ROLE_NAME = "DataConsumer";
|
public static final String DATA_CONSUMER_ROLE_NAME = "DataConsumer";
|
||||||
@ -454,6 +462,7 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
|
|||||||
this.supportsDataProducts = allowedFields.contains(FIELD_DATA_PRODUCTS);
|
this.supportsDataProducts = allowedFields.contains(FIELD_DATA_PRODUCTS);
|
||||||
this.supportsExperts = allowedFields.contains(FIELD_EXPERTS);
|
this.supportsExperts = allowedFields.contains(FIELD_EXPERTS);
|
||||||
this.supportsReviewers = allowedFields.contains(FIELD_REVIEWERS);
|
this.supportsReviewers = allowedFields.contains(FIELD_REVIEWERS);
|
||||||
|
this.supportsCertification = allowedFields.contains(FIELD_CERTIFICATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
@ -2432,6 +2441,100 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
|
|||||||
updateLifeCycle(json, entity, lifeCycle1, lifeCycle);
|
updateLifeCycle(json, entity, lifeCycle1, lifeCycle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void postPutPatch_entityCertification(TestInfo test) throws IOException {
|
||||||
|
if (!supportsCertification) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Create an entity without lifeCycle
|
||||||
|
T entity =
|
||||||
|
createEntity(
|
||||||
|
createRequest(getEntityName(test), "description", null, null), ADMIN_AUTH_HEADERS);
|
||||||
|
|
||||||
|
// Create Tag
|
||||||
|
TagResourceTest tagResourceTest = new TagResourceTest();
|
||||||
|
Tag certificationTag =
|
||||||
|
tagResourceTest.createEntity(tagResourceTest.createRequest(test, 0), ADMIN_AUTH_HEADERS);
|
||||||
|
TagLabel certificationLabel = EntityUtil.toTagLabel(certificationTag);
|
||||||
|
|
||||||
|
// Add certification using PATCH request
|
||||||
|
String json = JsonUtils.pojoToJson(entity);
|
||||||
|
AssetCertification certification = new AssetCertification().withTagLabel(certificationLabel);
|
||||||
|
entity.setCertification(certification);
|
||||||
|
try {
|
||||||
|
patchEntity(entity.getId(), json, entity, ADMIN_AUTH_HEADERS);
|
||||||
|
fail("Expected an exception to be thrown: Certification is not configured yet.");
|
||||||
|
} catch (HttpResponseException e) {
|
||||||
|
assertEquals(e.getStatusCode(), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure Certification Settings
|
||||||
|
String[] fqnParts = FullyQualifiedName.split(certificationLabel.getTagFQN());
|
||||||
|
String classification = FullyQualifiedName.getParentFQN(fqnParts);
|
||||||
|
|
||||||
|
AssetCertificationSettings certificationSettings =
|
||||||
|
new AssetCertificationSettings()
|
||||||
|
.withAllowedClassification(classification)
|
||||||
|
.withValidityPeriod("P30D");
|
||||||
|
|
||||||
|
SystemRepository systemRepository = Entity.getSystemRepository();
|
||||||
|
systemRepository.updateSetting(
|
||||||
|
new Settings()
|
||||||
|
.withConfigType(SettingsType.ASSET_CERTIFICATION_SETTINGS)
|
||||||
|
.withConfigValue(certificationSettings));
|
||||||
|
|
||||||
|
T patchedEntity = patchEntity(entity.getId(), json, entity, ADMIN_AUTH_HEADERS);
|
||||||
|
assertEquals(
|
||||||
|
patchedEntity.getCertification().getTagLabel().getTagFQN(), certificationLabel.getTagFQN());
|
||||||
|
assertEquals(
|
||||||
|
patchedEntity.getCertification().getAppliedDate(), System.currentTimeMillis(), 10 * 1000);
|
||||||
|
assertEquals(
|
||||||
|
(double)
|
||||||
|
(patchedEntity.getCertification().getExpiryDate()
|
||||||
|
- patchedEntity.getCertification().getAppliedDate()),
|
||||||
|
30D * 24 * 60 * 60 * 1000,
|
||||||
|
10 * 1000);
|
||||||
|
|
||||||
|
// Create Second Tag
|
||||||
|
Tag newCertificationTag =
|
||||||
|
tagResourceTest.createEntity(tagResourceTest.createRequest(test, 1), ADMIN_AUTH_HEADERS);
|
||||||
|
TagLabel newCertificationLabel = EntityUtil.toTagLabel(newCertificationTag);
|
||||||
|
|
||||||
|
// Configure Certification Settings
|
||||||
|
String[] newFqnParts = FullyQualifiedName.split(newCertificationLabel.getTagFQN());
|
||||||
|
String newClassification = FullyQualifiedName.getParentFQN(newFqnParts);
|
||||||
|
|
||||||
|
AssetCertificationSettings newCertificationSettings =
|
||||||
|
new AssetCertificationSettings()
|
||||||
|
.withAllowedClassification(newClassification)
|
||||||
|
.withValidityPeriod("P60D");
|
||||||
|
|
||||||
|
systemRepository.updateSetting(
|
||||||
|
new Settings()
|
||||||
|
.withConfigType(SettingsType.ASSET_CERTIFICATION_SETTINGS)
|
||||||
|
.withConfigValue(newCertificationSettings));
|
||||||
|
|
||||||
|
String newJson = JsonUtils.pojoToJson(entity);
|
||||||
|
AssetCertification newCertification =
|
||||||
|
new AssetCertification().withTagLabel(newCertificationLabel);
|
||||||
|
entity.setCertification(newCertification);
|
||||||
|
|
||||||
|
T newPatchedEntity = patchEntity(entity.getId(), newJson, entity, ADMIN_AUTH_HEADERS);
|
||||||
|
assertEquals(
|
||||||
|
newPatchedEntity.getCertification().getTagLabel().getTagFQN(),
|
||||||
|
newCertificationLabel.getTagFQN());
|
||||||
|
assertEquals(
|
||||||
|
newPatchedEntity.getCertification().getAppliedDate(),
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
10 * 1000);
|
||||||
|
assertEquals(
|
||||||
|
(double)
|
||||||
|
(newPatchedEntity.getCertification().getExpiryDate()
|
||||||
|
- newPatchedEntity.getCertification().getAppliedDate()),
|
||||||
|
60D * 24 * 60 * 60 * 1000,
|
||||||
|
10 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
private T updateLifeCycle(
|
private T updateLifeCycle(
|
||||||
String json, T entity, LifeCycle newLifeCycle, LifeCycle expectedLifeCycle)
|
String json, T entity, LifeCycle newLifeCycle, LifeCycle expectedLifeCycle)
|
||||||
throws HttpResponseException {
|
throws HttpResponseException {
|
||||||
|
|||||||
@ -108,6 +108,10 @@ public interface EntityInterface {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default AssetCertification getCertification() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
void setId(UUID id);
|
void setId(UUID id);
|
||||||
|
|
||||||
void setDescription(String description);
|
void setDescription(String description);
|
||||||
@ -178,6 +182,10 @@ public interface EntityInterface {
|
|||||||
/* no-op implementation to be overridden */
|
/* no-op implementation to be overridden */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void setCertification(AssetCertification certification) {
|
||||||
|
/* no-op implementation to be overridden */
|
||||||
|
}
|
||||||
|
|
||||||
<T extends EntityInterface> T withHref(URI href);
|
<T extends EntityInterface> T withHref(URI href);
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"$id": "https://open-metadata.org/schema/configuration/assetCertificationSettings.json",
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "AssetCertificationSettings",
|
||||||
|
"description": "This schema defines the Asset Certification Settings.",
|
||||||
|
"type": "object",
|
||||||
|
"javaType": "org.openmetadata.schema.configuration.AssetCertificationSettings",
|
||||||
|
"properties": {
|
||||||
|
"allowedClassification": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Classification that can be used for certifications."
|
||||||
|
},
|
||||||
|
"validityPeriod": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "ISO 8601 duration for the validity period."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["allowedClassification", "validityPeriod"],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
@ -105,6 +105,9 @@
|
|||||||
"description": "Life Cycle properties of the entity",
|
"description": "Life Cycle properties of the entity",
|
||||||
"$ref": "../../type/lifeCycle.json"
|
"$ref": "../../type/lifeCycle.json"
|
||||||
},
|
},
|
||||||
|
"certification": {
|
||||||
|
"$ref": "../../type/assetCertification.json"
|
||||||
|
},
|
||||||
"sourceHash": {
|
"sourceHash": {
|
||||||
"description": "Source hash of the entity",
|
"description": "Source hash of the entity",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -167,6 +167,9 @@
|
|||||||
"description": "Life Cycle properties of the entity",
|
"description": "Life Cycle properties of the entity",
|
||||||
"$ref": "../../type/lifeCycle.json"
|
"$ref": "../../type/lifeCycle.json"
|
||||||
},
|
},
|
||||||
|
"certification": {
|
||||||
|
"$ref": "../../type/assetCertification.json"
|
||||||
|
},
|
||||||
"sourceHash": {
|
"sourceHash": {
|
||||||
"description": "Source hash of the entity",
|
"description": "Source hash of the entity",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -155,6 +155,9 @@
|
|||||||
"description": "Life Cycle properties of the entity",
|
"description": "Life Cycle properties of the entity",
|
||||||
"$ref": "../../type/lifeCycle.json"
|
"$ref": "../../type/lifeCycle.json"
|
||||||
},
|
},
|
||||||
|
"certification": {
|
||||||
|
"$ref": "../../type/assetCertification.json"
|
||||||
|
},
|
||||||
"sourceHash": {
|
"sourceHash": {
|
||||||
"description": "Source hash of the entity",
|
"description": "Source hash of the entity",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -189,6 +189,9 @@
|
|||||||
"description": "Life Cycle properties of the entity",
|
"description": "Life Cycle properties of the entity",
|
||||||
"$ref": "../../type/lifeCycle.json"
|
"$ref": "../../type/lifeCycle.json"
|
||||||
},
|
},
|
||||||
|
"certification": {
|
||||||
|
"$ref": "../../type/assetCertification.json"
|
||||||
|
},
|
||||||
"sourceHash": {
|
"sourceHash": {
|
||||||
"description": "Source hash of the entity",
|
"description": "Source hash of the entity",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -143,6 +143,9 @@
|
|||||||
"description": "Life Cycle properties of the entity",
|
"description": "Life Cycle properties of the entity",
|
||||||
"$ref": "../../type/lifeCycle.json"
|
"$ref": "../../type/lifeCycle.json"
|
||||||
},
|
},
|
||||||
|
"certification": {
|
||||||
|
"$ref": "../../type/assetCertification.json"
|
||||||
|
},
|
||||||
"sourceHash": {
|
"sourceHash": {
|
||||||
"description": "Source hash of the entity",
|
"description": "Source hash of the entity",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -166,6 +166,9 @@
|
|||||||
"description": "Life Cycle properties of the entity",
|
"description": "Life Cycle properties of the entity",
|
||||||
"$ref": "../../type/lifeCycle.json"
|
"$ref": "../../type/lifeCycle.json"
|
||||||
},
|
},
|
||||||
|
"certification": {
|
||||||
|
"$ref": "../../type/assetCertification.json"
|
||||||
|
},
|
||||||
"sourceHash": {
|
"sourceHash": {
|
||||||
"description": "Source hash of the entity",
|
"description": "Source hash of the entity",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -121,6 +121,9 @@
|
|||||||
"description": "Life Cycle properties of the entity",
|
"description": "Life Cycle properties of the entity",
|
||||||
"$ref": "../../type/lifeCycle.json"
|
"$ref": "../../type/lifeCycle.json"
|
||||||
},
|
},
|
||||||
|
"certification": {
|
||||||
|
"$ref": "../../type/assetCertification.json"
|
||||||
|
},
|
||||||
"sourceHash": {
|
"sourceHash": {
|
||||||
"description": "Source hash of the entity",
|
"description": "Source hash of the entity",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -117,6 +117,9 @@
|
|||||||
"description": "Life Cycle properties of the entity",
|
"description": "Life Cycle properties of the entity",
|
||||||
"$ref": "../../type/lifeCycle.json"
|
"$ref": "../../type/lifeCycle.json"
|
||||||
},
|
},
|
||||||
|
"certification": {
|
||||||
|
"$ref": "../../type/assetCertification.json"
|
||||||
|
},
|
||||||
"sourceHash": {
|
"sourceHash": {
|
||||||
"description": "Source hash of the entity",
|
"description": "Source hash of the entity",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -195,6 +195,9 @@
|
|||||||
"extension": {
|
"extension": {
|
||||||
"description": "Entity extension data with custom attributes added to the entity.",
|
"description": "Entity extension data with custom attributes added to the entity.",
|
||||||
"$ref": "../../type/basic.json#/definitions/entityExtension"
|
"$ref": "../../type/basic.json#/definitions/entityExtension"
|
||||||
|
},
|
||||||
|
"certification": {
|
||||||
|
"$ref": "../../type/assetCertification.json"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["id", "name"],
|
"required": ["id", "name"],
|
||||||
|
|||||||
@ -285,6 +285,9 @@
|
|||||||
"description": "Life Cycle properties of the entity",
|
"description": "Life Cycle properties of the entity",
|
||||||
"$ref": "../../type/lifeCycle.json"
|
"$ref": "../../type/lifeCycle.json"
|
||||||
},
|
},
|
||||||
|
"certification": {
|
||||||
|
"$ref": "../../type/assetCertification.json"
|
||||||
|
},
|
||||||
"sourceHash": {
|
"sourceHash": {
|
||||||
"description": "Source hash of the entity",
|
"description": "Source hash of the entity",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -271,6 +271,9 @@
|
|||||||
"description": "Life Cycle properties of the entity",
|
"description": "Life Cycle properties of the entity",
|
||||||
"$ref": "../../type/lifeCycle.json"
|
"$ref": "../../type/lifeCycle.json"
|
||||||
},
|
},
|
||||||
|
"certification": {
|
||||||
|
"$ref": "../../type/assetCertification.json"
|
||||||
|
},
|
||||||
"sourceHash": {
|
"sourceHash": {
|
||||||
"description": "Source hash of the entity",
|
"description": "Source hash of the entity",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -248,6 +248,9 @@
|
|||||||
"description": "Life Cycle of the entity",
|
"description": "Life Cycle of the entity",
|
||||||
"$ref": "../../type/lifeCycle.json"
|
"$ref": "../../type/lifeCycle.json"
|
||||||
},
|
},
|
||||||
|
"certification": {
|
||||||
|
"$ref": "../../type/assetCertification.json"
|
||||||
|
},
|
||||||
"sourceHash": {
|
"sourceHash": {
|
||||||
"description": "Source hash of the entity",
|
"description": "Source hash of the entity",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -158,6 +158,9 @@
|
|||||||
"description": "Life Cycle properties of the entity",
|
"description": "Life Cycle properties of the entity",
|
||||||
"$ref": "../../type/lifeCycle.json"
|
"$ref": "../../type/lifeCycle.json"
|
||||||
},
|
},
|
||||||
|
"certification": {
|
||||||
|
"$ref": "../../type/assetCertification.json"
|
||||||
|
},
|
||||||
"sourceHash": {
|
"sourceHash": {
|
||||||
"description": "Source hash of the entity",
|
"description": "Source hash of the entity",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -1121,6 +1121,9 @@
|
|||||||
"description": "Life Cycle of the entity",
|
"description": "Life Cycle of the entity",
|
||||||
"$ref": "../../type/lifeCycle.json"
|
"$ref": "../../type/lifeCycle.json"
|
||||||
},
|
},
|
||||||
|
"certification": {
|
||||||
|
"$ref": "../../type/assetCertification.json"
|
||||||
|
},
|
||||||
"sourceHash": {
|
"sourceHash": {
|
||||||
"description": "Source hash of the entity",
|
"description": "Source hash of the entity",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -174,6 +174,9 @@
|
|||||||
"description": "Life Cycle properties of the entity",
|
"description": "Life Cycle properties of the entity",
|
||||||
"$ref": "../../type/lifeCycle.json"
|
"$ref": "../../type/lifeCycle.json"
|
||||||
},
|
},
|
||||||
|
"certification": {
|
||||||
|
"$ref": "../../type/assetCertification.json"
|
||||||
|
},
|
||||||
"sourceHash": {
|
"sourceHash": {
|
||||||
"description": "Source hash of the entity",
|
"description": "Source hash of the entity",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -30,7 +30,8 @@
|
|||||||
"slackInstaller",
|
"slackInstaller",
|
||||||
"slackState",
|
"slackState",
|
||||||
"profilerConfiguration",
|
"profilerConfiguration",
|
||||||
"searchSettings"
|
"searchSettings",
|
||||||
|
"assetCertificationSettings"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -76,6 +77,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$ref": "../configuration/searchSettings.json"
|
"$ref": "../configuration/searchSettings.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "../configuration/assetCertificationSettings.json"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
{ "$id": "https://open-metadata.org/schema/type/assetCertification.json",
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "AssetCertification",
|
||||||
|
"description": "Defines the Asset Certification schema.",
|
||||||
|
"javaType": "org.openmetadata.schema.type.AssetCertification",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"tagLabel": {
|
||||||
|
"$ref": "./tagLabel.json"
|
||||||
|
},
|
||||||
|
"appliedDate": {
|
||||||
|
"description": "The date when the certification was applied.",
|
||||||
|
"$ref": "basic.json#/definitions/timestamp"
|
||||||
|
},
|
||||||
|
"expiryDate": {
|
||||||
|
"description": "The date when the certification expires.",
|
||||||
|
"$ref": "basic.json#/definitions/timestamp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["tagLabel", "appliedDate", "expiryDate"],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user