use of io.cdap.cdap.api.artifact.ArtifactSummary in project cdap by caskdata.
the class ApplicationLifecycleService method getLatestAppArtifactForUpgrade.
/**
* Finds latest application artifact for given application and current artifact for upgrading application.
* If no artifact found then returns current artifact as the candidate.
*
* @param appId application Id to find latest app artifact for.
* @param currentArtifactId current artifact used by application.
* @param allowedArtifactScopes artifact scopes to search in for finding candidate artifacts.
* @param allowSnapshot whether to consider snapshot version of artifacts or not for upgrade.
* @return {@link ArtifactSummary} for the artifact to be used for upgrade purpose.
* @throws NotFoundException if there is no artifact available for given artifact.
* @throws Exception if there was an exception during finding candidate artifact.
*/
private ArtifactSummary getLatestAppArtifactForUpgrade(ApplicationId appId, ArtifactId currentArtifactId, Set<ArtifactScope> allowedArtifactScopes, boolean allowSnapshot) throws Exception {
List<ArtifactSummary> availableArtifacts = new ArrayList<>();
// At the least, current artifact should be in the set of available artifacts.
availableArtifacts.add(ArtifactSummary.from(currentArtifactId));
// Find candidate artifacts from all scopes we need to consider.
for (ArtifactScope scope : allowedArtifactScopes) {
NamespaceId artifactNamespaceToConsider = ArtifactScope.SYSTEM.equals(scope) ? NamespaceId.SYSTEM : appId.getParent();
List<ArtifactSummary> artifacts;
try {
artifacts = artifactRepository.getArtifactSummaries(artifactNamespaceToConsider, currentArtifactId.getName(), Integer.MAX_VALUE, ArtifactSortOrder.ASC);
} catch (ArtifactNotFoundException e) {
// This can happen if we are looking for candidate artifact in multiple namespace.
continue;
}
for (ArtifactSummary artifactSummary : artifacts) {
ArtifactVersion artifactVersion = new ArtifactVersion(artifactSummary.getVersion());
// Consider if it is a non-snapshot version artifact or it is a snapshot version than allowSnapshot is true.
if ((artifactVersion.isSnapshot() && allowSnapshot) || !artifactVersion.isSnapshot()) {
availableArtifacts.add(artifactSummary);
}
}
}
// Find the artifact with latest version.
Optional<ArtifactSummary> newArtifactCandidate = availableArtifacts.stream().max(Comparator.comparing(artifactSummary -> new ArtifactVersion(artifactSummary.getVersion())));
io.cdap.cdap.proto.id.ArtifactId currentArtifact = new io.cdap.cdap.proto.id.ArtifactId(appId.getNamespace(), currentArtifactId.getName(), currentArtifactId.getVersion().getVersion());
return newArtifactCandidate.orElseThrow(() -> new ArtifactNotFoundException(currentArtifact));
}
use of io.cdap.cdap.api.artifact.ArtifactSummary in project cdap by caskdata.
the class ApplicationLifecycleService method updateApp.
/**
* Update an existing application. An application's configuration and artifact version can be updated.
*
* @param appId the id of the application to update
* @param appRequest the request to update the application, including new config and artifact
* @param programTerminator a program terminator that will stop programs that are removed when updating an app.
* For example, if an update removes a flow, the terminator defines how to stop that flow.
* @return information about the deployed application
* @throws ApplicationNotFoundException if the specified application does not exist
* @throws ArtifactNotFoundException if the requested artifact does not exist
* @throws InvalidArtifactException if the specified artifact is invalid. For example, if the artifact name changed,
* if the version is an invalid version, or the artifact contains no app classes
* @throws Exception if there was an exception during the deployment pipeline. This exception will often wrap
* the actual exception
*/
public ApplicationWithPrograms updateApp(ApplicationId appId, AppRequest appRequest, ProgramTerminator programTerminator) throws Exception {
// Check if the current user has admin privileges on it before updating.
accessEnforcer.enforce(appId, authenticationContext.getPrincipal(), StandardPermission.UPDATE);
// check that app exists
ApplicationSpecification currentSpec = store.getApplication(appId);
if (currentSpec == null) {
throw new ApplicationNotFoundException(appId);
}
ArtifactId currentArtifact = currentSpec.getArtifactId();
// if no artifact is given, use the current one.
ArtifactId newArtifactId = currentArtifact;
// otherwise, check requested artifact is valid and use it
ArtifactSummary requestedArtifact = appRequest.getArtifact();
if (requestedArtifact != null) {
// cannot change artifact name, only artifact version.
if (!currentArtifact.getName().equals(requestedArtifact.getName())) {
throw new InvalidArtifactException(String.format(" Only artifact version updates are allowed. Cannot change from artifact '%s' to '%s'.", currentArtifact.getName(), requestedArtifact.getName()));
}
if (!currentArtifact.getScope().equals(requestedArtifact.getScope())) {
throw new InvalidArtifactException("Only artifact version updates are allowed. " + "Cannot change from a non-system artifact to a system artifact or vice versa.");
}
// check requested artifact version is valid
ArtifactVersion requestedVersion = new ArtifactVersion(requestedArtifact.getVersion());
if (requestedVersion.getVersion() == null) {
throw new InvalidArtifactException(String.format("Requested artifact version '%s' is invalid", requestedArtifact.getVersion()));
}
newArtifactId = new ArtifactId(currentArtifact.getName(), requestedVersion, currentArtifact.getScope());
}
// ownerAdmin.getImpersonationPrincipal will give the owner which will be impersonated for the application
// irrespective of the version
SecurityUtil.verifyOwnerPrincipal(appId, appRequest.getOwnerPrincipal(), ownerAdmin);
Object requestedConfigObj = appRequest.getConfig();
// if config is null, use the previous config. Shouldn't use a static GSON since the request Config object can
// be a user class, otherwise there will be ClassLoader leakage.
String requestedConfigStr = requestedConfigObj == null ? currentSpec.getConfiguration() : new Gson().toJson(requestedConfigObj);
Id.Artifact artifactId = Id.Artifact.fromEntityId(Artifacts.toProtoArtifactId(appId.getParent(), newArtifactId));
return deployApp(appId.getParent(), appId.getApplication(), null, artifactId, requestedConfigStr, programTerminator, ownerAdmin.getOwner(appId), appRequest.canUpdateSchedules());
}
use of io.cdap.cdap.api.artifact.ArtifactSummary in project cdap by caskdata.
the class ApplicationClientTestRun method testAll.
@Test
public void testAll() throws Exception {
ApplicationId app = NamespaceId.DEFAULT.app(FakeApp.NAME);
Assert.assertEquals(0, appClient.list(NamespaceId.DEFAULT).size());
// deploy app
LOG.info("Deploying app");
appClient.deploy(NamespaceId.DEFAULT, createAppJarFile(FakeApp.class, FakeApp.NAME, "1.0.0-SNAPSHOT"));
appClient.waitForDeployed(app, 30, TimeUnit.SECONDS);
Assert.assertEquals(1, appClient.list(NamespaceId.DEFAULT).size());
try {
// check program list
LOG.info("Checking program list for app");
Map<ProgramType, List<ProgramRecord>> programs = appClient.listProgramsByType(app);
verifyProgramNames(FakeApp.MAPREDUCES, programs.get(ProgramType.MAPREDUCE));
verifyProgramNames(FakeApp.WORKFLOWS, programs.get(ProgramType.WORKFLOW));
verifyProgramNames(FakeApp.SERVICES, programs.get(ProgramType.SERVICE));
verifyProgramNames(FakeApp.MAPREDUCES, appClient.listPrograms(app, ProgramType.MAPREDUCE));
verifyProgramNames(FakeApp.WORKFLOWS, appClient.listPrograms(app, ProgramType.WORKFLOW));
verifyProgramNames(FakeApp.SERVICES, appClient.listPrograms(app, ProgramType.SERVICE));
verifyProgramNames(FakeApp.MAPREDUCES, appClient.listAllPrograms(NamespaceId.DEFAULT, ProgramType.MAPREDUCE));
verifyProgramNames(FakeApp.WORKFLOWS, appClient.listAllPrograms(NamespaceId.DEFAULT, ProgramType.WORKFLOW));
verifyProgramNames(FakeApp.SERVICES, appClient.listAllPrograms(NamespaceId.DEFAULT, ProgramType.SERVICE));
verifyProgramRecords(FakeApp.ALL_PROGRAMS, appClient.listAllPrograms(NamespaceId.DEFAULT));
ApplicationDetail appDetail = appClient.get(app);
ArtifactSummary expected = new ArtifactSummary(FakeApp.NAME, "1.0.0-SNAPSHOT");
Assert.assertEquals(expected, appDetail.getArtifact());
} finally {
// delete app
LOG.info("Deleting app");
appClient.delete(app);
appClient.waitForDeleted(app, 30, TimeUnit.SECONDS);
Assert.assertEquals(0, appClient.list(NamespaceId.DEFAULT).size());
}
}
use of io.cdap.cdap.api.artifact.ArtifactSummary in project cdap by caskdata.
the class ApplicationClientTestRun method testAppUpdate.
@Test
public void testAppUpdate() throws Exception {
String artifactName = "cfg-programs";
ArtifactId artifactIdV1 = NamespaceId.DEFAULT.artifact(artifactName, "1.0.0");
ArtifactId artifactIdV2 = NamespaceId.DEFAULT.artifact(artifactName, "2.0.0");
ApplicationId appId = NamespaceId.DEFAULT.app("ProgramsApp");
artifactClient.add(NamespaceId.DEFAULT, artifactName, () -> Files.newInputStream(createAppJarFile(ConfigurableProgramsApp.class).toPath()), "1.0.0");
artifactClient.add(NamespaceId.DEFAULT, artifactName, () -> Files.newInputStream(createAppJarFile(ConfigurableProgramsApp2.class).toPath()), "2.0.0");
try {
// deploy the app with just the worker
ConfigurableProgramsApp.Programs conf = new ConfigurableProgramsApp.Programs("worker1", null, "dataset1");
AppRequest<ConfigurableProgramsApp.Programs> request = new AppRequest<>(new ArtifactSummary(artifactIdV1.getArtifact(), artifactIdV1.getVersion()), conf);
appClient.deploy(appId, request);
// should only have the worker
Assert.assertTrue(appClient.listPrograms(appId, ProgramType.SERVICE).isEmpty());
Assert.assertEquals(1, appClient.listPrograms(appId, ProgramType.WORKER).size());
// update to use just the service
conf = new ConfigurableProgramsApp.Programs(null, "service", "dataset1");
request = new AppRequest<>(new ArtifactSummary(artifactIdV1.getArtifact(), artifactIdV1.getVersion()), conf);
appClient.update(appId, request);
// should only have the service
Assert.assertTrue(appClient.listPrograms(appId, ProgramType.WORKER).isEmpty());
Assert.assertEquals(1, appClient.listPrograms(appId, ProgramType.SERVICE).size());
// check nonexistent app is not found
try {
appClient.update(NamespaceId.DEFAULT.app("ghost"), request);
Assert.fail();
} catch (NotFoundException e) {
// expected
}
// check different artifact name is invalid
request = new AppRequest<>(new ArtifactSummary("ghost", artifactIdV1.getVersion()), conf);
try {
appClient.update(appId, request);
Assert.fail();
} catch (BadRequestException e) {
// expected
}
// check nonexistent artifact is not found
request = new AppRequest<>(new ArtifactSummary(artifactIdV1.getArtifact(), "0.0.1"), conf);
try {
appClient.update(appId, request);
Assert.fail();
} catch (NotFoundException e) {
// expected
}
// update artifact version. This version uses a different app class with that can add a workflow
ConfigurableProgramsApp2.Programs conf2 = new ConfigurableProgramsApp2.Programs(null, null, "workflow1", "dataset1");
AppRequest<ConfigurableProgramsApp2.Programs> request2 = new AppRequest<>(new ArtifactSummary(artifactIdV2.getArtifact(), artifactIdV2.getVersion()), conf2);
appClient.update(appId, request2);
// should only have a single workflow
Assert.assertTrue(appClient.listPrograms(appId, ProgramType.WORKER).isEmpty());
Assert.assertTrue(appClient.listPrograms(appId, ProgramType.SERVICE).isEmpty());
Assert.assertEquals(1, appClient.listPrograms(appId, ProgramType.WORKFLOW).size());
} finally {
appClient.delete(appId);
appClient.waitForDeleted(appId, 30, TimeUnit.SECONDS);
artifactClient.delete(artifactIdV1);
artifactClient.delete(artifactIdV2);
}
}
use of io.cdap.cdap.api.artifact.ArtifactSummary in project cdap by caskdata.
the class ApplicationClientTestRun method testArtifactFilter.
@Test
public void testArtifactFilter() throws Exception {
ApplicationId appId1 = NamespaceId.DEFAULT.app(FakeApp.NAME);
ApplicationId appId2 = NamespaceId.DEFAULT.app("fake2");
ApplicationId appId3 = NamespaceId.DEFAULT.app("fake3");
try {
// app1 should use fake-1.0.0-SNAPSHOT
appClient.deploy(NamespaceId.DEFAULT, createAppJarFile(FakeApp.class, "otherfake", "1.0.0-SNAPSHOT"));
appClient.deploy(NamespaceId.DEFAULT, createAppJarFile(FakeApp.class, "fake", "0.1.0-SNAPSHOT"));
// app1 should end up with fake-1.0.0-SNAPSHOT
appClient.deploy(NamespaceId.DEFAULT, createAppJarFile(FakeApp.class, "fake", "1.0.0-SNAPSHOT"));
// app2 should use fake-0.1.0-SNAPSHOT
appClient.deploy(appId2, new AppRequest<Config>(new ArtifactSummary("fake", "0.1.0-SNAPSHOT")));
// app3 should use otherfake-1.0.0-SNAPSHOT
appClient.deploy(appId3, new AppRequest<Config>(new ArtifactSummary("otherfake", "1.0.0-SNAPSHOT")));
appClient.waitForDeployed(appId1, 30, TimeUnit.SECONDS);
appClient.waitForDeployed(appId2, 30, TimeUnit.SECONDS);
appClient.waitForDeployed(appId3, 30, TimeUnit.SECONDS);
// check calls that should return nothing
// these don't match anything
Assert.assertTrue(appClient.list(NamespaceId.DEFAULT, "ghost", null).isEmpty());
Assert.assertTrue(appClient.list(NamespaceId.DEFAULT, (String) null, "1.0.0").isEmpty());
Assert.assertTrue(appClient.list(NamespaceId.DEFAULT, "ghost", "1.0.0").isEmpty());
// these match one but not the other
Assert.assertTrue(appClient.list(NamespaceId.DEFAULT, "otherfake", "0.1.0-SNAPSHOT").isEmpty());
Assert.assertTrue(appClient.list(NamespaceId.DEFAULT, "fake", "1.0.0").isEmpty());
// check filter by name only
Set<ApplicationRecord> apps = Sets.newHashSet(appClient.list(NamespaceId.DEFAULT, "fake", null));
Set<ApplicationRecord> expected = ImmutableSet.of(new ApplicationRecord(new ArtifactSummary("fake", "1.0.0-SNAPSHOT"), appId1, ""), new ApplicationRecord(new ArtifactSummary("fake", "0.1.0-SNAPSHOT"), appId2, ""));
Assert.assertEquals(expected, apps);
apps = Sets.newHashSet(appClient.list(NamespaceId.DEFAULT, "otherfake", null));
expected = ImmutableSet.of(new ApplicationRecord(new ArtifactSummary("otherfake", "1.0.0-SNAPSHOT"), appId3, ""));
Assert.assertEquals(expected, apps);
// check filter by multiple names
apps = Sets.newHashSet(appClient.list(NamespaceId.DEFAULT, ImmutableSet.of("fake", "otherfake"), null));
expected = ImmutableSet.of(new ApplicationRecord(new ArtifactSummary("otherfake", "1.0.0-SNAPSHOT"), appId3, ""), new ApplicationRecord(new ArtifactSummary("fake", "1.0.0-SNAPSHOT"), appId1, ""), new ApplicationRecord(new ArtifactSummary("fake", "0.1.0-SNAPSHOT"), appId2, ""));
Assert.assertEquals(expected, apps);
// check filter by version only
apps = Sets.newHashSet(appClient.list(NamespaceId.DEFAULT, (String) null, "0.1.0-SNAPSHOT"));
expected = ImmutableSet.of(new ApplicationRecord(new ArtifactSummary("fake", "0.1.0-SNAPSHOT"), appId2, ""));
Assert.assertEquals(expected, apps);
apps = Sets.newHashSet(appClient.list(NamespaceId.DEFAULT, (String) null, "1.0.0-SNAPSHOT"));
expected = ImmutableSet.of(new ApplicationRecord(new ArtifactSummary("fake", "1.0.0-SNAPSHOT"), appId1, ""), new ApplicationRecord(new ArtifactSummary("otherfake", "1.0.0-SNAPSHOT"), appId3, ""));
Assert.assertEquals(expected, apps);
// check filter by both
apps = Sets.newHashSet(appClient.list(NamespaceId.DEFAULT, "fake", "0.1.0-SNAPSHOT"));
expected = ImmutableSet.of(new ApplicationRecord(new ArtifactSummary("fake", "0.1.0-SNAPSHOT"), appId2, ""));
Assert.assertEquals(expected, apps);
} finally {
appClient.deleteAll(NamespaceId.DEFAULT);
appClient.waitForDeleted(appId1, 30, TimeUnit.SECONDS);
appClient.waitForDeleted(appId2, 30, TimeUnit.SECONDS);
appClient.waitForDeleted(appId3, 30, TimeUnit.SECONDS);
Assert.assertEquals(0, appClient.list(NamespaceId.DEFAULT).size());
}
}
Aggregations