use of io.cdap.cdap.common.id.Id in project cdap by caskdata.
the class DefaultArtifactRepository method addSystemArtifacts.
@Override
public void addSystemArtifacts() throws Exception {
// scan the directory for artifact .jar files and config files for those artifacts
Map<Id.Artifact, SystemArtifactInfo> systemArtifacts = new HashMap<>();
for (File systemArtifactDir : systemArtifactDirs) {
for (File jarFile : DirUtils.listFiles(systemArtifactDir, "jar")) {
// parse id from filename
Id.Artifact artifactId;
try {
artifactId = Id.Artifact.parse(Id.Namespace.SYSTEM, jarFile.getName());
} catch (IllegalArgumentException e) {
LOG.warn(String.format("Skipping system artifact '%s' because the name is invalid: ", e.getMessage()));
continue;
}
// check for a corresponding .json config file
String artifactFileName = jarFile.getName();
String configFileName = artifactFileName.substring(0, artifactFileName.length() - ".jar".length()) + ".json";
File configFile = new File(systemArtifactDir, configFileName);
try {
// read and parse the config file if it exists. Otherwise use an empty config with the artifact filename
ArtifactConfig artifactConfig = configFile.isFile() ? configReader.read(artifactId.getNamespace(), configFile) : new ArtifactConfig();
validateParentSet(artifactId, artifactConfig.getParents());
validatePluginSet(artifactConfig.getPlugins());
systemArtifacts.put(artifactId, new SystemArtifactInfo(artifactId, jarFile, artifactConfig));
} catch (InvalidArtifactException e) {
LOG.warn(String.format("Could not add system artifact '%s' because it is invalid.", artifactFileName), e);
}
}
}
// child -> parents
Multimap<Id.Artifact, Id.Artifact> childToParents = HashMultimap.create();
// parent -> children
Multimap<Id.Artifact, Id.Artifact> parentToChildren = HashMultimap.create();
Set<Id.Artifact> remainingArtifacts = new HashSet<>();
// build mapping from child to parents and from parents to children
for (SystemArtifactInfo child : systemArtifacts.values()) {
Id.Artifact childId = child.getArtifactId();
remainingArtifacts.add(childId);
for (SystemArtifactInfo potentialParent : systemArtifacts.values()) {
Id.Artifact potentialParentId = potentialParent.getArtifactId();
// skip if we're looking at ourselves
if (childId.equals(potentialParentId)) {
continue;
}
if (child.getConfig().hasParent(potentialParentId)) {
childToParents.put(childId, potentialParentId);
parentToChildren.put(potentialParentId, childId);
}
}
}
if (!remainingArtifacts.isEmpty()) {
ExecutorService executorService = Executors.newFixedThreadPool(Math.min(maxArtifactLoadParallelism, remainingArtifacts.size()), Threads.createDaemonThreadFactory("system-artifact-loader-%d"));
try {
// loop until there is no change
boolean artifactsAdded = true;
while (!remainingArtifacts.isEmpty() && artifactsAdded) {
artifactsAdded = loadSystemArtifacts(executorService, systemArtifacts, remainingArtifacts, parentToChildren, childToParents);
}
} finally {
executorService.shutdownNow();
}
if (!remainingArtifacts.isEmpty()) {
LOG.warn("Unable to add system artifacts {} due to cyclic dependencies", Joiner.on(",").join(remainingArtifacts));
}
}
}
use of io.cdap.cdap.common.id.Id in project cdap by caskdata.
the class AppLifecycleHttpHandler method getAllApps.
/**
* Returns a list of applications associated with a namespace.
*/
@GET
@Path("/apps")
public void getAllApps(HttpRequest request, HttpResponder responder, @PathParam("namespace-id") String namespaceId, @QueryParam("artifactName") String artifactName, @QueryParam("artifactVersion") String artifactVersion, @QueryParam("pageToken") String pageToken, @QueryParam("pageSize") Integer pageSize, @QueryParam("orderBy") SortOrder orderBy, @QueryParam("nameFilter") String nameFilter) throws Exception {
NamespaceId namespace = validateNamespace(namespaceId);
Set<String> names = new HashSet<>();
if (!Strings.isNullOrEmpty(artifactName)) {
for (String name : Splitter.on(',').split(artifactName)) {
names.add(name);
}
}
if (Optional.ofNullable(pageSize).orElse(0) != 0) {
JsonPaginatedListResponder.respond(GSON, responder, APP_LIST_PAGINATED_KEY, jsonListResponder -> {
AtomicReference<ApplicationRecord> lastRecord = new AtomicReference<>(null);
ScanApplicationsRequest scanRequest = getScanRequest(namespaceId, artifactVersion, pageToken, pageSize, orderBy, nameFilter, names);
boolean pageLimitReached = applicationLifecycleService.scanApplications(scanRequest, appDetail -> {
ApplicationRecord record = new ApplicationRecord(appDetail);
jsonListResponder.send(record);
lastRecord.set(record);
});
ApplicationRecord record = lastRecord.get();
return !pageLimitReached || record == null ? null : record.getName() + EntityId.IDSTRING_PART_SEPARATOR + record.getAppVersion();
});
} else {
ScanApplicationsRequest scanRequest = getScanRequest(namespaceId, artifactVersion, pageToken, null, orderBy, nameFilter, names);
JsonWholeListResponder.respond(GSON, responder, jsonListResponder -> applicationLifecycleService.scanApplications(scanRequest, d -> jsonListResponder.send(new ApplicationRecord(d))));
}
}
use of io.cdap.cdap.common.id.Id in project cdap by caskdata.
the class AbstractProgramRuntimeService method list.
@Override
public Map<RunId, RuntimeInfo> list(ProgramType type) {
Map<RunId, RuntimeInfo> result = new HashMap<>();
Lock lock = runtimeInfosLock.readLock();
lock.lock();
try {
result.putAll(runtimeInfos.row(type));
} finally {
lock.unlock();
}
// Add any missing RuntimeInfo from the remote twill runner
if (remoteTwillRunnerService == null) {
return Collections.unmodifiableMap(result);
}
for (TwillRunner.LiveInfo liveInfo : remoteTwillRunnerService.lookupLive()) {
ProgramId programId = TwillAppNames.fromTwillAppName(liveInfo.getApplicationName(), false);
if (programId == null || !programId.getType().equals(type)) {
continue;
}
for (TwillController controller : liveInfo.getControllers()) {
// For remote twill runner, the twill run id and cdap run id are the same
RunId runId = controller.getRunId();
if (result.computeIfAbsent(runId, rid -> createRuntimeInfo(programId, runId, controller)) == null) {
LOG.warn("Unable to create runtime info for program {} with run id {}", programId, runId);
}
}
}
return Collections.unmodifiableMap(result);
}
use of io.cdap.cdap.common.id.Id in project cdap by caskdata.
the class SystemAppManagementServiceTest method testSystemAppManagementServiceE2E.
/**
* Tests SystemAppManagementService's upgrade method end to end by running this scenario:
* 1. Creates a system app config for an application into corresponding directory with artifact version VERSION1.
* 2. Successfully read and load the config.
* 3. Runs all steps to enable a system app , tests SystemAppEnableExecutor.
* 4. Deploys the VERSION1 app and runs all programs corresponding to the app.
* 5. Checks status of a continuously running program, i.e a service program.
* 6. Updates system app config with app version upgraded to VERSION2.
* 7. On restart of SystemAppManagementService, app should kill old running programs and start program again.
*/
@Test
public void testSystemAppManagementServiceE2E() throws Exception {
systemConfigDir = TEMPORARY_FOLDER.newFolder("demo-sys-app-config-dir");
cConf.set(Constants.SYSTEM_APP_CONFIG_DIR, systemConfigDir.getAbsolutePath());
systemAppManagementService = new SystemAppManagementService(cConf, applicationLifecycleService, programLifecycleService);
Id.Artifact artifactId1 = Id.Artifact.from(Id.Namespace.DEFAULT, "App", VERSION1);
addAppArtifact(artifactId1, AllProgramsApp.class);
createEnableSysAppConfigFile(artifactId1, "demo.json");
systemAppManagementService.startUp();
ApplicationId appId1 = NamespaceId.DEFAULT.app(AllProgramsApp.NAME);
ProgramId serviceId1 = appId1.program(ProgramType.SERVICE, AllProgramsApp.NoOpService.NAME);
waitState(serviceId1, RUNNING);
Assert.assertEquals(RUNNING, getProgramStatus(serviceId1));
// Program shouldn't be killed first time it is started.
assertProgramRuns(serviceId1, ProgramRunStatus.KILLED, 0);
systemAppManagementService.shutDown();
// New system app config with newer artifact version.
Id.Artifact artifactId2 = Id.Artifact.from(Id.Namespace.DEFAULT, "App", VERSION2);
addAppArtifact(artifactId2, AllProgramsApp.class);
createEnableSysAppConfigFile(artifactId2, "demo.json");
// SystemAppManagement restarts again.
systemAppManagementService.startUp();
// Program ID still stays the same.
waitState(serviceId1, RUNNING);
Assert.assertEquals(RUNNING, getProgramStatus(serviceId1));
assertProgramRuns(serviceId1, ProgramRunStatus.KILLED, 1);
}
use of io.cdap.cdap.common.id.Id in project cdap by caskdata.
the class ApplicationLifecycleService method upgradeApplication.
/**
* Upgrades an existing application by upgrading application artifact versions and plugin artifact versions.
*
* @param appId the id of the application to upgrade.
* @param allowedArtifactScopes artifact scopes allowed while looking for latest artifacts for upgrade.
* @param allowSnapshot whether to consider snapshot version of artifacts or not for upgrade.
* @throws IllegalStateException if something unexpected happened during upgrade.
* @throws IOException if there was an IO error during initializing application class from artifact.
* @throws JsonIOException if there was an error in serializing or deserializing app config.
* @throws UnsupportedOperationException if application does not support upgrade operation.
* @throws InvalidArtifactException if candidate application artifact is invalid for upgrade purpose.
* @throws NotFoundException if any object related to upgrade is not found like application/artifact.
* @throws Exception if there was an exception during the upgrade of application. This exception will often wrap
* the actual exception
*/
public void upgradeApplication(ApplicationId appId, Set<ArtifactScope> allowedArtifactScopes, boolean allowSnapshot) 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) {
LOG.info("Application {} not found for upgrade.", appId);
throw new NotFoundException(appId);
}
ArtifactId currentArtifact = currentSpec.getArtifactId();
ArtifactSummary candidateArtifact = getLatestAppArtifactForUpgrade(appId, currentArtifact, allowedArtifactScopes, allowSnapshot);
ArtifactVersion candidateArtifactVersion = new ArtifactVersion(candidateArtifact.getVersion());
// Current artifact should not have higher version than candidate artifact.
if (currentArtifact.getVersion().compareTo(candidateArtifactVersion) > 0) {
String error = String.format("The current artifact has a version higher %s than any existing artifact.", currentArtifact.getVersion());
throw new InvalidArtifactException(error);
}
ArtifactId newArtifactId = new ArtifactId(candidateArtifact.getName(), candidateArtifactVersion, candidateArtifact.getScope());
Id.Artifact newArtifact = Id.Artifact.fromEntityId(Artifacts.toProtoArtifactId(appId.getParent(), newArtifactId));
ArtifactDetail newArtifactDetail = artifactRepository.getArtifact(newArtifact);
updateApplicationInternal(appId, currentSpec.getConfiguration(), programId -> {
}, newArtifactDetail, Collections.singletonList(ApplicationConfigUpdateAction.UPGRADE_ARTIFACT), allowedArtifactScopes, allowSnapshot, ownerAdmin.getOwner(appId), false);
}
Aggregations