use of co.cask.cdap.proto.id.NamespaceId in project cdap by caskdata.
the class DefaultNamespaceAdmin method create.
/**
* Creates a new namespace
*
* @param metadata the {@link NamespaceMeta} for the new namespace to be created
* @throws NamespaceAlreadyExistsException if the specified namespace already exists
*/
@Override
@AuthEnforce(entities = "instanceId", enforceOn = InstanceId.class, actions = Action.ADMIN)
public synchronized void create(final NamespaceMeta metadata) throws Exception {
// TODO: CDAP-1427 - This should be transactional, but we don't support transactions on files yet
Preconditions.checkArgument(metadata != null, "Namespace metadata should not be null.");
NamespaceId namespace = metadata.getNamespaceId();
if (exists(namespace)) {
throw new NamespaceAlreadyExistsException(namespace);
}
// If this namespace has custom mapping then validate the given custom mapping
if (hasCustomMapping(metadata)) {
validateCustomMapping(metadata);
}
// check that the user has configured either both of none of the following configuration: principal and keytab URI
boolean hasValidKerberosConf = false;
if (metadata.getConfig() != null) {
String configuredPrincipal = metadata.getConfig().getPrincipal();
String configuredKeytabURI = metadata.getConfig().getKeytabURI();
if ((!Strings.isNullOrEmpty(configuredPrincipal) && Strings.isNullOrEmpty(configuredKeytabURI)) || (Strings.isNullOrEmpty(configuredPrincipal) && !Strings.isNullOrEmpty(configuredKeytabURI))) {
throw new BadRequestException(String.format("Either neither or both of the following two configurations must be configured. " + "Configured principal: %s, Configured keytabURI: %s", configuredPrincipal, configuredKeytabURI));
}
hasValidKerberosConf = true;
}
// check that if explore as principal is explicitly set to false then user has kerberos configuration
if (!metadata.getConfig().isExploreAsPrincipal() && !hasValidKerberosConf) {
throw new BadRequestException(String.format("No kerberos principal or keytab-uri was provided while '%s' was set to true.", NamespaceConfig.EXPLORE_AS_PRINCIPAL));
}
// Namespace can be created. Grant all the permissions to the user.
Principal principal = authenticationContext.getPrincipal();
privilegesManager.grant(namespace, principal, EnumSet.allOf(Action.class));
// Also grant the user who will execute programs in this namespace all privileges on the namespace
String executionUserName;
if (SecurityUtil.isKerberosEnabled(cConf) && !NamespaceId.SYSTEM.equals(namespace)) {
String namespacePrincipal = metadata.getConfig().getPrincipal();
if (Strings.isNullOrEmpty(namespacePrincipal)) {
executionUserName = new KerberosName(SecurityUtil.getMasterPrincipal(cConf)).getShortName();
} else {
executionUserName = new KerberosName(namespacePrincipal).getShortName();
}
} else {
executionUserName = UserGroupInformation.getCurrentUser().getShortUserName();
}
Principal executionUser = new Principal(executionUserName, Principal.PrincipalType.USER);
privilegesManager.grant(namespace, executionUser, EnumSet.allOf(Action.class));
// store the meta first in the namespace store because namespacedLocationFactory needs to look up location
// mapping from namespace config
nsStore.create(metadata);
try {
UserGroupInformation ugi;
if (NamespaceId.DEFAULT.equals(namespace)) {
ugi = UserGroupInformation.getCurrentUser();
} else {
ugi = impersonator.getUGI(namespace);
}
ImpersonationUtils.doAs(ugi, new Callable<Void>() {
@Override
public Void call() throws Exception {
storageProviderNamespaceAdmin.get().create(metadata);
return null;
}
});
} catch (Throwable t) {
// failed to create namespace in underlying storage so delete the namespace meta stored in the store earlier
deleteNamespaceMeta(metadata.getNamespaceId());
privilegesManager.revoke(namespace);
throw new NamespaceCannotBeCreatedException(namespace, t);
}
LOG.info("Namespace {} created with meta {}", metadata.getNamespaceId(), metadata);
}
use of co.cask.cdap.proto.id.NamespaceId in project cdap by caskdata.
the class SystemArtifactsAuthorizationTest method testAuthorizationForSystemArtifacts.
@Test
public void testAuthorizationForSystemArtifacts() throws Exception {
artifactRepository.addSystemArtifacts();
// alice should not be able to refresh system artifacts because she does not have write privileges on the
// CDAP instance
SecurityRequestContext.setUserId(ALICE.getName());
try {
artifactRepository.addSystemArtifacts();
Assert.fail("Adding system artifacts should have failed because alice does not have write privileges on " + "the CDAP instance.");
} catch (UnauthorizedException expected) {
// expected
}
// grant alice write privileges on the CDAP instance
authorizer.grant(NamespaceId.SYSTEM, ALICE, Collections.singleton(Action.WRITE));
Assert.assertEquals(Collections.singleton(new Privilege(NamespaceId.SYSTEM, Action.WRITE)), authorizer.listPrivileges(ALICE));
// refreshing system artifacts should succeed now
artifactRepository.addSystemArtifacts();
SecurityRequestContext.setUserId("bob");
// deleting a system artifact should fail because bob does not have admin privileges on the artifact
try {
artifactRepository.deleteArtifact(SYSTEM_ARTIFACT.toId());
Assert.fail("Deleting a system artifact should have failed because alice does not have admin privileges on " + "the CDAP instance.");
} catch (UnauthorizedException expected) {
// expected
}
// grant alice admin privileges on the CDAP instance, so she can create a namespace
SecurityRequestContext.setUserId(ALICE.getName());
authorizer.grant(instance, ALICE, Collections.singleton(Action.ADMIN));
NamespaceId namespaceId = new NamespaceId("test");
namespaceAdmin.create(new NamespaceMeta.Builder().setName(namespaceId.getNamespace()).build());
authorizer.revoke(instance);
// test that system artifacts are available to everyone
List<ArtifactSummary> artifacts = artifactRepository.getArtifactSummaries(namespaceId, true);
Assert.assertEquals(1, artifacts.size());
ArtifactSummary artifactSummary = artifacts.get(0);
Assert.assertEquals(SYSTEM_ARTIFACT.getArtifact(), artifactSummary.getName());
Assert.assertEquals(SYSTEM_ARTIFACT.getVersion(), artifactSummary.getVersion());
Assert.assertEquals(SYSTEM_ARTIFACT.getNamespace(), artifactSummary.getScope().name().toLowerCase());
// test the getArtifact API
ArtifactDetail artifactDetail = artifactRepository.getArtifact(SYSTEM_ARTIFACT.toId());
co.cask.cdap.api.artifact.ArtifactId artifactId = artifactDetail.getDescriptor().getArtifactId();
Assert.assertEquals(SYSTEM_ARTIFACT.getArtifact(), artifactId.getName());
Assert.assertEquals(SYSTEM_ARTIFACT.getVersion(), artifactId.getVersion().getVersion());
Assert.assertEquals(SYSTEM_ARTIFACT.getNamespace(), artifactId.getScope().name().toLowerCase());
namespaceAdmin.delete(namespaceId);
authorizer.enforce(SYSTEM_ARTIFACT, ALICE, EnumSet.allOf(Action.class));
authorizer.enforce(NamespaceId.SYSTEM, ALICE, Action.WRITE);
// deleting system artifact should succeed as alice, because alice added the artifacts, so she should have all
// privileges on it
artifactRepository.deleteArtifact(SYSTEM_ARTIFACT.toId());
}
use of co.cask.cdap.proto.id.NamespaceId in project cdap by caskdata.
the class MapReduceProgramRunnerTest method testMapreduceWithObjectStore.
@Test
public void testMapreduceWithObjectStore() throws Exception {
// Deploy apps to another namespace and test cross-namespace access meanwhile
final ApplicationWithPrograms app = deployApp(new NamespaceId("someOtherNameSpace").toId(), AppWithMapReduceUsingObjectStore.class);
final ObjectStore<String> input = datasetCache.getDataset("someOtherNameSpace", "keys");
// Get dataset from a non existing namespace
try {
datasetCache.getDataset("nonExistingNameSpace", "keys");
Assert.fail("getDataset() should throw an exception when accessing dataset from a non-existing namespace.");
} catch (DatasetInstantiationException e) {
// expected
}
final String testString = "persisted data";
//Populate some input
Transactions.createTransactionExecutor(txExecutorFactory, (TransactionAware) input).execute(new TransactionExecutor.Subroutine() {
@Override
public void apply() {
input.write(Bytes.toBytes(testString), testString);
input.write(Bytes.toBytes("distributed systems"), "distributed systems");
}
});
runProgram(app, AppWithMapReduceUsingObjectStore.ComputeCounts.class, false, true);
final KeyValueTable output = datasetCache.getDataset("someOtherNameSpace", "count");
//read output and verify result
Transactions.createTransactionExecutor(txExecutorFactory, output).execute(new TransactionExecutor.Subroutine() {
@Override
public void apply() {
byte[] val = output.read(Bytes.toBytes(testString));
Assert.assertTrue(val != null);
Assert.assertEquals(Bytes.toString(val), Integer.toString(testString.length()));
val = output.read(Bytes.toBytes("distributed systems"));
Assert.assertTrue(val != null);
Assert.assertEquals(Bytes.toString(val), "19");
}
});
}
use of co.cask.cdap.proto.id.NamespaceId in project cdap by caskdata.
the class ProgramLifecycleHttpHandlerTest method testUpdateSchedule.
private void testUpdateSchedule(ApplicationId appV2Id) throws Exception {
// intentionally keep two ScheduleUpdateDetail's to test backward compatibility
ScheduleUpdateDetail scheduleUpdateDetail = new ScheduleUpdateDetail("updatedDescription", new RunConstraints(5), "0 4 * * *", null, null, ImmutableMap.of("twoKey", "twoValue", "someKey", "newValue"));
ScheduleUpdateDetail invalidUpdateDetail = new ScheduleUpdateDetail("updatedDescription", null, null, "streamName", null, ImmutableMap.<String, String>of());
ScheduleDetail validScheduleDetail = new ScheduleDetail(AppWithSchedule.SCHEDULE, "updatedDescription", null, ImmutableMap.<String, String>of(), new StreamSizeTrigger(new NamespaceId(TEST_NAMESPACE1).stream(AppWithSchedule.STREAM), 10), ImmutableList.<Constraint>of(new ConcurrencyConstraint(5)), null);
// trying to update schedule for a non-existing app should fail
HttpResponse response = updateSchedule(TEST_NAMESPACE1, "nonExistingApp", null, AppWithSchedule.SCHEDULE, scheduleUpdateDetail);
Assert.assertEquals(HttpResponseStatus.NOT_FOUND.getCode(), response.getStatusLine().getStatusCode());
// trying to update a non-existing schedule should fail
response = updateSchedule(TEST_NAMESPACE1, AppWithSchedule.NAME, null, "NonExistingSchedule", scheduleUpdateDetail);
Assert.assertEquals(HttpResponseStatus.NOT_FOUND.getCode(), response.getStatusLine().getStatusCode());
// trying to update a time schedule with stream schedule detail containing null dataTriggerMB should fail
response = updateSchedule(TEST_NAMESPACE1, AppWithSchedule.NAME, null, AppWithSchedule.SCHEDULE, invalidUpdateDetail);
Assert.assertEquals(HttpResponseStatus.BAD_REQUEST.getCode(), response.getStatusLine().getStatusCode());
// trying to update a time schedule with stream schedule detail containing both
// stream name and dataTriggerMB should succeed
response = updateSchedule(TEST_NAMESPACE1, AppWithSchedule.NAME, null, AppWithSchedule.SCHEDULE, validScheduleDetail);
Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode());
// should be able to update an existing stream size schedule with a valid new time schedule
response = updateSchedule(TEST_NAMESPACE1, AppWithSchedule.NAME, null, AppWithSchedule.SCHEDULE, scheduleUpdateDetail);
Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode());
// verify that the schedule information for updated
ScheduleDetail schedule = getSchedule(TEST_NAMESPACE1, AppWithSchedule.NAME, null, AppWithSchedule.SCHEDULE);
Assert.assertEquals("updatedDescription", schedule.getDescription());
Assert.assertEquals("0 4 * * *", ((TimeTrigger) schedule.getTrigger()).getCronExpression());
Assert.assertEquals(new ProtoConstraint.ConcurrencyConstraint(5), schedule.getConstraints().get(0));
// the properties should have been replaced
Assert.assertEquals(2, schedule.getProperties().size());
Assert.assertEquals("newValue", schedule.getProperties().get("someKey"));
Assert.assertEquals("twoValue", schedule.getProperties().get("twoKey"));
// the old property should not exist
Assert.assertNull(schedule.getProperties().get("oneKey"));
// the above update should not have affected the schedule for the other version of the app
schedule = getSchedule(TEST_NAMESPACE1, AppWithSchedule.NAME, appV2Id.getVersion(), AppWithSchedule.SCHEDULE);
Assert.assertNotEquals("updatedDescription", schedule.getDescription());
Assert.assertEquals("0/15 * * * * ?", ((TimeTrigger) schedule.getTrigger()).getCronExpression());
// try to update the schedule again but this time with property as null. It should retain the old properties
ScheduleDetail scheduleDetail = new ScheduleDetail(AppWithSchedule.SCHEDULE, "updatedDescription", null, null, new TimeTrigger("0 4 * * *"), null, null);
response = updateSchedule(TEST_NAMESPACE1, AppWithSchedule.NAME, null, AppWithSchedule.SCHEDULE, scheduleDetail);
Assert.assertEquals(HttpResponseStatus.OK.getCode(), response.getStatusLine().getStatusCode());
schedule = getSchedule(TEST_NAMESPACE1, AppWithSchedule.NAME, null, AppWithSchedule.SCHEDULE);
Assert.assertEquals(2, schedule.getProperties().size());
Assert.assertEquals("newValue", schedule.getProperties().get("someKey"));
Assert.assertEquals("twoValue", schedule.getProperties().get("twoKey"));
Assert.assertEquals(new ProtoConstraint.ConcurrencyConstraint(5), schedule.getConstraints().get(0));
}
use of co.cask.cdap.proto.id.NamespaceId in project cdap by caskdata.
the class DefaultStoreTest method testRemoveAll.
@Test
public void testRemoveAll() throws Exception {
ApplicationSpecification spec = Specifications.from(new WordCountApp());
NamespaceId namespaceId = new NamespaceId("account1");
ApplicationId appId = namespaceId.app("application1");
store.addApplication(appId, spec);
Assert.assertNotNull(store.getApplication(appId));
// removing flow
store.removeAll(namespaceId);
Assert.assertNull(store.getApplication(appId));
}
Aggregations