use of co.cask.cdap.proto.Id 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 that app exists
ApplicationSpecification currentSpec = store.getApplication(appId);
if (currentSpec == null) {
throw new ApplicationNotFoundException(appId);
}
// App exists. Check if the current user has admin privileges on it before updating. The user's write privileges on
// the namespace will get enforced in the deployApp method.
authorizationEnforcer.enforce(appId, authenticationContext.getPrincipal(), Action.ADMIN);
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 = Artifacts.toArtifactId(appId.getParent(), newArtifactId).toId();
return deployApp(appId.getParent(), appId.getApplication(), null, artifactId, requestedConfigStr, programTerminator, ownerAdmin.getOwner(appId), appRequest.canUpdateSchedules());
}
use of co.cask.cdap.proto.Id in project cdap by caskdata.
the class ApplicationLifecycleService method deleteApp.
// deletes without performs checks that no programs are running
/**
* Delete the specified application without performing checks that its programs are stopped.
*
* @param appId the id of the application to delete
* @param spec the spec of the application to delete
* @throws Exception
*/
private void deleteApp(final ApplicationId appId, ApplicationSpecification spec) throws Exception {
Id.Application idApplication = appId.toId();
// enforce ADMIN privileges on the app
authorizationEnforcer.enforce(appId, authenticationContext.getPrincipal(), Action.ADMIN);
// first remove all privileges on the app
revokePrivileges(appId, spec);
//Delete the schedules
scheduler.deleteSchedules(appId);
deleteMetrics(appId);
//Delete all preferences of the application and of all its programs
deletePreferences(appId);
// TODO: This should be unified with the DeletedProgramHandlerStage
for (final FlowSpecification flowSpecification : spec.getFlows().values()) {
Id.Program flowProgramId = Id.Program.from(idApplication, ProgramType.FLOW, flowSpecification.getName());
// Collects stream name to all group ids consuming that stream
final Multimap<String, Long> streamGroups = HashMultimap.create();
for (FlowletConnection connection : flowSpecification.getConnections()) {
if (connection.getSourceType() == FlowletConnection.Type.STREAM) {
long groupId = FlowUtils.generateConsumerGroupId(flowProgramId, connection.getTargetName());
streamGroups.put(connection.getSourceName(), groupId);
}
}
// Remove all process states and group states for each stream
final String namespace = String.format("%s.%s", flowProgramId.getApplicationId(), flowProgramId.getId());
impersonator.doAs(appId, new Callable<Void>() {
// TODO: (CDAP-7326) since one worker or flow can only be ran by a single instance of APP, (also a single
// version), should delete flow for each version
@Override
public Void call() throws Exception {
for (Map.Entry<String, Collection<Long>> entry : streamGroups.asMap().entrySet()) {
streamConsumerFactory.dropAll(appId.getParent().stream(entry.getKey()), namespace, entry.getValue());
}
queueAdmin.dropAllForFlow(appId.flow(flowSpecification.getName()));
return null;
}
});
}
ApplicationSpecification appSpec = store.getApplication(appId);
deleteAppMetadata(appId, appSpec);
deleteRouteConfig(appId, appSpec);
store.deleteWorkflowStats(appId);
store.removeApplication(appId);
try {
// delete the owner as it has already been determined that this is the only version of the app
ownerAdmin.delete(appId);
} catch (Exception e) {
LOG.warn("Failed to delete app owner principal for application {} if one existed while deleting the " + "application.", appId);
}
try {
usageRegistry.unregister(appId);
} catch (Exception e) {
LOG.warn("Failed to unregister usage of app: {}", appId, e);
}
}
use of co.cask.cdap.proto.Id in project cdap by caskdata.
the class ArtifactHttpHandler method writeProperties.
@PUT
@Path("/namespaces/{namespace-id}/artifacts/{artifact-name}/versions/{artifact-version}/properties")
@AuditPolicy(AuditDetail.REQUEST_BODY)
public void writeProperties(HttpRequest request, HttpResponder responder, @PathParam("namespace-id") String namespaceId, @PathParam("artifact-name") String artifactName, @PathParam("artifact-version") String artifactVersion) throws Exception {
NamespaceId namespace = NamespaceId.SYSTEM.getNamespace().equalsIgnoreCase(namespaceId) ? NamespaceId.SYSTEM : validateAndGetNamespace(namespaceId);
Id.Artifact artifactId = validateAndGetArtifactId(namespace, artifactName, artifactVersion);
Map<String, String> properties;
try (Reader reader = new InputStreamReader(new ChannelBufferInputStream(request.getContent()), Charsets.UTF_8)) {
properties = GSON.fromJson(reader, MAP_STRING_STRING_TYPE);
} catch (JsonSyntaxException e) {
throw new BadRequestException("Json Syntax Error while parsing properties from request. " + "Please check that the properties are a json map from string to string.", e);
} catch (IOException e) {
throw new BadRequestException("Unable to read properties from the request.", e);
}
try {
artifactRepository.writeArtifactProperties(artifactId, properties);
responder.sendStatus(HttpResponseStatus.OK);
} catch (IOException e) {
LOG.error("Exception writing properties for artifact {}.", artifactId, e);
responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, "Error adding properties to artifact.");
}
}
use of co.cask.cdap.proto.Id in project cdap by caskdata.
the class ArtifactHttpHandler method getProperty.
@GET
@Path("/namespaces/{namespace-id}/artifacts/{artifact-name}/versions/{artifact-version}/properties/{property}")
public void getProperty(HttpRequest request, HttpResponder responder, @PathParam("namespace-id") String namespaceId, @PathParam("artifact-name") String artifactName, @PathParam("artifact-version") String artifactVersion, @PathParam("property") String key, @QueryParam("scope") @DefaultValue("user") String scope) throws Exception {
NamespaceId namespace = validateAndGetScopedNamespace(Ids.namespace(namespaceId), scope);
Id.Artifact artifactId = validateAndGetArtifactId(namespace, artifactName, artifactVersion);
try {
ArtifactDetail detail = artifactRepository.getArtifact(artifactId);
responder.sendString(HttpResponseStatus.OK, detail.getMeta().getProperties().get(key));
} catch (IOException e) {
LOG.error("Exception reading property for artifact {}.", artifactId, e);
responder.sendString(HttpResponseStatus.INTERNAL_SERVER_ERROR, "Error reading properties for artifact.");
}
}
use of co.cask.cdap.proto.Id in project cdap by caskdata.
the class NamespacedIdCodec method deserializeProgramId.
private Id.Program deserializeProgramId(JsonObject id) {
Id.Application app = deserializeApplicationId(id.getAsJsonObject("application"));
ProgramType programType = ProgramType.valueOf(id.get("type").getAsString().toUpperCase());
String programId = id.get("id").getAsString();
return Id.Program.from(app, programType, programId);
}
Aggregations