public OMClientResponse validateAndUpdateCache()

in hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantAssignUserAccessIdRequest.java [190:361]


  public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, ExecutionContext context) {
    final long transactionLogIndex = context.getIndex();
    final OMMultiTenantManager multiTenantManager =
        ozoneManager.getMultiTenantManager();

    final OMMetrics omMetrics = ozoneManager.getMetrics();
    omMetrics.incNumTenantAssignUsers();

    OMClientResponse omClientResponse = null;
    final OMResponse.Builder omResponse =
        OmResponseUtil.getOMResponseBuilder(getOmRequest());

    final UpdateGetS3SecretRequest updateGetS3SecretRequest =
        getOmRequest().getUpdateGetS3SecretRequest();
    final String accessId = updateGetS3SecretRequest.getKerberosID();
    final String awsSecret = updateGetS3SecretRequest.getAwsSecret();

    boolean acquiredVolumeLock = false;
    final Map<String, String> auditMap = new HashMap<>();
    final OMMetadataManager omMetadataManager =
        ozoneManager.getMetadataManager();

    final TenantAssignUserAccessIdRequest request =
        getOmRequest().getTenantAssignUserAccessIdRequest();
    final String tenantId = request.getTenantId();
    final String userPrincipal = request.getUserPrincipal();

    Preconditions.checkState(accessId.equals(request.getAccessId()));
    Exception exception = null;

    String volumeName = null;

    try {
      volumeName = ozoneManager.getMultiTenantManager()
          .getTenantVolumeName(tenantId);

      mergeOmLockDetails(omMetadataManager.getLock().acquireWriteLock(
          VOLUME_LOCK, volumeName));
      acquiredVolumeLock = getOmLockDetails().isLockAcquired();

      // Expect tenant existence in tenantStateTable
      if (!omMetadataManager.getTenantStateTable().isExist(tenantId)) {
        LOG.error("tenant {} doesn't exist", tenantId);
        throw new OMException("tenant '" + tenantId + "' doesn't exist",
            ResultCodes.TENANT_NOT_FOUND);
      }

      // Expect accessId absence from tenantAccessIdTable
      if (omMetadataManager.getTenantAccessIdTable().isExist(accessId)) {
        LOG.error("accessId {} already exists", accessId);
        throw new OMException("accessId '" + accessId + "' already exists!",
            ResultCodes.TENANT_USER_ACCESS_ID_ALREADY_EXISTS);
      }

      OmDBUserPrincipalInfo principalInfo = omMetadataManager
          .getPrincipalToAccessIdsTable().getIfExist(userPrincipal);
      // Reject if the user is already assigned to the tenant
      if (principalInfo != null) {
        // If any existing accessIds are assigned to the same tenant, throw ex
        // TODO: There is room for perf improvement. add a map in OMMTM.
        for (final String existingAccId : principalInfo.getAccessIds()) {
          final OmDBAccessIdInfo accessIdInfo =
              omMetadataManager.getTenantAccessIdTable().get(existingAccId);
          if (accessIdInfo == null) {
            LOG.error("Metadata error: accessIdInfo is null for accessId '{}'. "
                + "Ignoring.", existingAccId);
            throw new OMException("accessIdInfo is null",
                ResultCodes.INVALID_ACCESS_ID);
          }
          if (tenantId.equals(accessIdInfo.getTenantId())) {
            throw new OMException("The same user is not allowed to be assigned "
                + "to the same tenant more than once. User '" + userPrincipal
                + "' is already assigned to tenant '" + tenantId + "' with "
                + "accessId '" + existingAccId + "'.",
                ResultCodes.TENANT_USER_ACCESS_ID_ALREADY_EXISTS);
          }
        }
      }

      final S3SecretValue s3SecretValue = S3SecretValue.of(accessId, awsSecret, transactionLogIndex);

      // Add to tenantAccessIdTable
      final OmDBAccessIdInfo omDBAccessIdInfo = new OmDBAccessIdInfo.Builder()
          .setTenantId(tenantId)
          .setUserPrincipal(userPrincipal)
          .setIsAdmin(false)
          .setIsDelegatedAdmin(false)
          .build();
      omMetadataManager.getTenantAccessIdTable().addCacheEntry(
          new CacheKey<>(accessId),
          CacheValue.get(transactionLogIndex, omDBAccessIdInfo));

      // Add to principalToAccessIdsTable
      if (principalInfo == null) {
        principalInfo = new OmDBUserPrincipalInfo.Builder()
            .setAccessIds(new TreeSet<>(Collections.singleton(accessId)))
            .build();
      } else {
        principalInfo.addAccessId(accessId);
      }
      omMetadataManager.getPrincipalToAccessIdsTable().addCacheEntry(
          new CacheKey<>(userPrincipal),
          CacheValue.get(transactionLogIndex, principalInfo));

      // Expect accessId absence from S3SecretTable
      ozoneManager.getS3SecretManager()
          .doUnderLock(accessId, s3SecretManager -> {
            if (s3SecretManager.hasS3Secret(accessId)) {
              LOG.error("accessId '{}' already exists in S3SecretTable",
                  accessId);
              throw new OMException("accessId '" + accessId +
                  "' already exists in S3SecretTable",
                  ResultCodes.TENANT_USER_ACCESS_ID_ALREADY_EXISTS);
            }

            s3SecretManager
                .updateCache(accessId, s3SecretValue);
            return null;
          });

      // Update tenant cache
      multiTenantManager.getCacheOp()
          .assignUserToTenant(userPrincipal, tenantId, accessId);

      // Generate response
      omResponse.setTenantAssignUserAccessIdResponse(
          TenantAssignUserAccessIdResponse.newBuilder()
              .setS3Secret(S3Secret.newBuilder()
                  .setAwsSecret(awsSecret).setKerberosID(accessId))
              .build());
      omClientResponse = new OMTenantAssignUserAccessIdResponse(
          omResponse.build(), s3SecretValue, userPrincipal,
          accessId, omDBAccessIdInfo, principalInfo,
          ozoneManager.getS3SecretManager());
    } catch (IOException | InvalidPathException ex) {
      exception = ex;
      omResponse.setTenantAssignUserAccessIdResponse(
          TenantAssignUserAccessIdResponse.newBuilder().build());
      omClientResponse = new OMTenantAssignUserAccessIdResponse(
          createErrorOMResponse(omResponse, exception));
    } finally {
      if (acquiredVolumeLock) {
        Preconditions.checkNotNull(volumeName);
        mergeOmLockDetails(
            omMetadataManager.getLock().releaseWriteLock(VOLUME_LOCK,
                volumeName));
      }
      // Release authorizer write lock
      multiTenantManager.getAuthorizerLock().unlockWriteInOMRequest();
      if (omClientResponse != null) {
        omClientResponse.setOmLockDetails(getOmLockDetails());
      }
    }

    // Audit
    auditMap.put(OzoneConsts.TENANT, tenantId);
    auditMap.put("user", userPrincipal);
    auditMap.put("accessId", accessId);
    markForAudit(ozoneManager.getAuditLogger(), buildAuditMessage(
        OMAction.TENANT_ASSIGN_USER_ACCESSID, auditMap, exception,
            getOmRequest().getUserInfo()));

    if (exception == null) {
      LOG.info("Assigned user '{}' to tenant '{}' with accessId '{}'",
          userPrincipal, tenantId, accessId);
    } else {
      LOG.error("Failed to assign '{}' to tenant '{}' with accessId '{}': {}",
          userPrincipal, tenantId, accessId, exception.getMessage());
      omMetrics.incNumTenantAssignUserFails();
    }
    return omClientResponse;
  }