|
25 | 25 | import com.google.common.collect.Lists;
|
26 | 26 | import com.google.common.collect.Sets;
|
27 | 27 | import java.lang.reflect.Field;
|
| 28 | +import java.net.MalformedURLException; |
28 | 29 | import java.net.URI;
|
29 | 30 | import java.net.URL;
|
| 31 | +import java.util.ArrayList; |
30 | 32 | import java.util.Collections;
|
31 | 33 | import java.util.HashMap;
|
32 | 34 | import java.util.HashSet;
|
@@ -551,153 +553,95 @@ protected void internalDeleteNamespaceForcefully(AsyncResponse asyncResponse, bo
|
551 | 553 | });
|
552 | 554 | }
|
553 | 555 |
|
554 |
| - protected void internalDeleteNamespaceBundle(String bundleRange, boolean authoritative, boolean force) { |
555 |
| - if (force) { |
556 |
| - internalDeleteNamespaceBundleForcefully(bundleRange, authoritative); |
557 |
| - } else { |
558 |
| - internalDeleteNamespaceBundle(bundleRange, authoritative); |
559 |
| - } |
560 |
| - } |
561 |
| - |
562 | 556 | @SuppressWarnings("deprecation")
|
563 |
| - protected void internalDeleteNamespaceBundle(String bundleRange, boolean authoritative) { |
564 |
| - validateNamespaceOperation(namespaceName, NamespaceOperation.DELETE_BUNDLE); |
565 |
| - validatePoliciesReadOnlyAccess(); |
566 |
| - |
567 |
| - // ensure that non-global namespace is directed to the correct cluster |
568 |
| - if (!namespaceName.isGlobal()) { |
569 |
| - validateClusterOwnership(namespaceName.getCluster()); |
570 |
| - } |
571 |
| - |
572 |
| - Policies policies = getNamespacePolicies(namespaceName); |
573 |
| - // ensure the local cluster is the only cluster for the global namespace configuration |
574 |
| - try { |
575 |
| - if (namespaceName.isGlobal()) { |
576 |
| - if (policies.replication_clusters.size() > 1) { |
577 |
| - // There are still more than one clusters configured for the global namespace |
578 |
| - throw new RestException(Status.PRECONDITION_FAILED, "Cannot delete the global namespace " |
579 |
| - + namespaceName + ". There are still more than one replication clusters configured."); |
580 |
| - } |
581 |
| - if (policies.replication_clusters.size() == 1 |
582 |
| - && !policies.replication_clusters.contains(config().getClusterName())) { |
583 |
| - // the only replication cluster is other cluster, redirect |
584 |
| - String replCluster = Lists.newArrayList(policies.replication_clusters).get(0); |
585 |
| - ClusterData replClusterData = |
586 |
| - clusterResources().getCluster(replCluster) |
587 |
| - .orElseThrow(() -> new RestException(Status.NOT_FOUND, |
588 |
| - "Cluster " + replCluster + " does not exist")); |
589 |
| - URL replClusterUrl; |
590 |
| - if (!config().isTlsEnabled() || !isRequestHttps()) { |
591 |
| - replClusterUrl = new URL(replClusterData.getServiceUrl()); |
592 |
| - } else if (StringUtils.isNotBlank(replClusterData.getServiceUrlTls())) { |
593 |
| - replClusterUrl = new URL(replClusterData.getServiceUrlTls()); |
594 |
| - } else { |
595 |
| - throw new RestException(Status.PRECONDITION_FAILED, |
596 |
| - "The replication cluster does not provide TLS encrypted service"); |
597 |
| - } |
598 |
| - URI redirect = UriBuilder.fromUri(uri.getRequestUri()).host(replClusterUrl.getHost()) |
599 |
| - .port(replClusterUrl.getPort()).replaceQueryParam("authoritative", false).build(); |
600 |
| - if (log.isDebugEnabled()) { |
601 |
| - log.debug("[{}] Redirecting the rest call to {}: cluster={}", |
602 |
| - clientAppId(), redirect, replCluster); |
| 557 | + protected CompletableFuture<Void> internalDeleteNamespaceBundleAsync(String bundleRange, boolean authoritative, |
| 558 | + boolean force) { |
| 559 | + return validateNamespaceOperationAsync(namespaceName, NamespaceOperation.DELETE_BUNDLE) |
| 560 | + .thenCompose(__ -> validatePoliciesReadOnlyAccessAsync()) |
| 561 | + .thenCompose(__ -> { |
| 562 | + if (!namespaceName.isGlobal()) { |
| 563 | + return validateClusterOwnershipAsync(namespaceName.getCluster()); |
603 | 564 | }
|
604 |
| - throw new WebApplicationException(Response.temporaryRedirect(redirect).build()); |
605 |
| - } |
606 |
| - } |
607 |
| - } catch (WebApplicationException wae) { |
608 |
| - throw wae; |
609 |
| - } catch (Exception e) { |
610 |
| - throw new RestException(e); |
611 |
| - } |
612 |
| - |
613 |
| - try { |
614 |
| - NamespaceBundle bundle = validateNamespaceBundleOwnership(namespaceName, policies.bundles, bundleRange, |
615 |
| - authoritative, true); |
616 |
| - List<String> topics = pulsar().getNamespaceService().getListOfPersistentTopics(namespaceName) |
617 |
| - .get(config().getMetadataStoreOperationTimeoutSeconds(), TimeUnit.SECONDS); |
618 |
| - for (String topic : topics) { |
619 |
| - NamespaceBundle topicBundle = pulsar().getNamespaceService() |
620 |
| - .getBundle(TopicName.get(topic)); |
621 |
| - if (bundle.equals(topicBundle)) { |
622 |
| - throw new RestException(Status.CONFLICT, "Cannot delete non empty bundle"); |
623 |
| - } |
624 |
| - } |
625 |
| - |
626 |
| - // remove from owned namespace map and ephemeral node from ZK |
627 |
| - pulsar().getNamespaceService().removeOwnedServiceUnit(bundle); |
628 |
| - } catch (WebApplicationException wae) { |
629 |
| - throw wae; |
630 |
| - } catch (Exception e) { |
631 |
| - log.error("[{}] Failed to remove namespace bundle {}/{}", clientAppId(), namespaceName.toString(), |
632 |
| - bundleRange, e); |
633 |
| - throw new RestException(e); |
634 |
| - } |
635 |
| - } |
636 |
| - |
637 |
| - @SuppressWarnings("deprecation") |
638 |
| - protected void internalDeleteNamespaceBundleForcefully(String bundleRange, boolean authoritative) { |
639 |
| - validateNamespaceOperation(namespaceName, NamespaceOperation.DELETE_BUNDLE); |
640 |
| - validatePoliciesReadOnlyAccess(); |
| 565 | + return CompletableFuture.completedFuture(null); |
| 566 | + }) |
| 567 | + .thenCompose(__ -> getNamespacePoliciesAsync(namespaceName)) |
| 568 | + .thenCompose(policies -> { |
| 569 | + CompletableFuture<Void> future = CompletableFuture.completedFuture(null); |
| 570 | + if (namespaceName.isGlobal()) { |
641 | 571 |
|
642 |
| - // ensure that non-global namespace is directed to the correct cluster |
643 |
| - if (!namespaceName.isGlobal()) { |
644 |
| - validateClusterOwnership(namespaceName.getCluster()); |
645 |
| - } |
| 572 | + if (policies.replication_clusters.size() > 1) { |
| 573 | + // There are still more than one clusters configured for the global namespace |
| 574 | + throw new RestException(Status.PRECONDITION_FAILED, "Cannot delete the global namespace " |
| 575 | + + namespaceName |
| 576 | + + ". There are still more than one replication clusters configured."); |
| 577 | + } |
| 578 | + if (policies.replication_clusters.size() == 1 |
| 579 | + && !policies.replication_clusters.contains(config().getClusterName())) { |
| 580 | + // the only replication cluster is other cluster, redirect |
| 581 | + String replCluster = Lists.newArrayList(policies.replication_clusters).get(0); |
| 582 | + future = clusterResources().getClusterAsync(replCluster) |
| 583 | + .thenCompose(clusterData -> { |
| 584 | + if (clusterData.isEmpty()) { |
| 585 | + throw new RestException(Status.NOT_FOUND, |
| 586 | + "Cluster " + replCluster + " does not exist"); |
| 587 | + } |
| 588 | + ClusterData replClusterData = clusterData.get(); |
| 589 | + URL replClusterUrl; |
| 590 | + try { |
| 591 | + if (!config().isTlsEnabled() || !isRequestHttps()) { |
| 592 | + replClusterUrl = new URL(replClusterData.getServiceUrl()); |
| 593 | + } else if (StringUtils.isNotBlank(replClusterData.getServiceUrlTls())) { |
| 594 | + replClusterUrl = new URL(replClusterData.getServiceUrlTls()); |
| 595 | + } else { |
| 596 | + throw new RestException(Status.PRECONDITION_FAILED, |
| 597 | + "The replication cluster does not provide TLS encrypted " |
| 598 | + + "service"); |
| 599 | + } |
| 600 | + } catch (MalformedURLException malformedURLException) { |
| 601 | + throw new RestException(malformedURLException); |
| 602 | + } |
646 | 603 |
|
647 |
| - Policies policies = getNamespacePolicies(namespaceName); |
648 |
| - // ensure the local cluster is the only cluster for the global namespace configuration |
649 |
| - try { |
650 |
| - if (namespaceName.isGlobal()) { |
651 |
| - if (policies.replication_clusters.size() > 1) { |
652 |
| - // There are still more than one clusters configured for the global namespace |
653 |
| - throw new RestException(Status.PRECONDITION_FAILED, "Cannot delete the global namespace " |
654 |
| - + namespaceName + ". There are still more than one replication clusters configured."); |
655 |
| - } |
656 |
| - if (policies.replication_clusters.size() == 1 |
657 |
| - && !policies.replication_clusters.contains(config().getClusterName())) { |
658 |
| - // the only replication cluster is other cluster, redirect |
659 |
| - String replCluster = Lists.newArrayList(policies.replication_clusters).get(0); |
660 |
| - ClusterData replClusterData = |
661 |
| - clusterResources().getCluster(replCluster) |
662 |
| - .orElseThrow(() -> new RestException(Status.NOT_FOUND, |
663 |
| - "Cluster " + replCluster + " does not exist")); |
664 |
| - URL replClusterUrl; |
665 |
| - if (!config().isTlsEnabled() || !isRequestHttps()) { |
666 |
| - replClusterUrl = new URL(replClusterData.getServiceUrl()); |
667 |
| - } else if (StringUtils.isNotBlank(replClusterData.getServiceUrlTls())) { |
668 |
| - replClusterUrl = new URL(replClusterData.getServiceUrlTls()); |
669 |
| - } else { |
670 |
| - throw new RestException(Status.PRECONDITION_FAILED, |
671 |
| - "The replication cluster does not provide TLS encrypted service"); |
672 |
| - } |
673 |
| - URI redirect = UriBuilder.fromUri(uri.getRequestUri()).host(replClusterUrl.getHost()) |
674 |
| - .port(replClusterUrl.getPort()) |
675 |
| - .replaceQueryParam("authoritative", false).build(); |
676 |
| - if (log.isDebugEnabled()) { |
677 |
| - log.debug("[{}] Redirecting the rest call to {}: cluster={}", |
678 |
| - clientAppId(), redirect, replCluster); |
| 604 | + URI redirect = |
| 605 | + UriBuilder.fromUri(uri.getRequestUri()).host(replClusterUrl.getHost()) |
| 606 | + .port(replClusterUrl.getPort()) |
| 607 | + .replaceQueryParam("authoritative", false).build(); |
| 608 | + if (log.isDebugEnabled()) { |
| 609 | + log.debug("[{}] Redirecting the rest call to {}: cluster={}", |
| 610 | + clientAppId(), redirect, replCluster); |
| 611 | + } |
| 612 | + throw new WebApplicationException(Response.temporaryRedirect(redirect).build()); |
| 613 | + }); |
| 614 | + } |
679 | 615 | }
|
680 |
| - throw new WebApplicationException(Response.temporaryRedirect(redirect).build()); |
681 |
| - } |
682 |
| - } |
683 |
| - } catch (WebApplicationException wae) { |
684 |
| - throw wae; |
685 |
| - } catch (Exception e) { |
686 |
| - throw new RestException(e); |
687 |
| - } |
| 616 | + return future.thenCompose(__ -> { |
| 617 | + NamespaceBundle bundle = |
| 618 | + validateNamespaceBundleOwnership(namespaceName, policies.bundles, bundleRange, |
| 619 | + authoritative, true); |
| 620 | + return pulsar().getNamespaceService().getListOfPersistentTopics(namespaceName) |
| 621 | + .thenCompose(topics -> { |
| 622 | + CompletableFuture<Void> deleteTopicsFuture = |
| 623 | + CompletableFuture.completedFuture(null); |
| 624 | + if (!force) { |
| 625 | + List<CompletableFuture<NamespaceBundle>> futures = new ArrayList<>(); |
| 626 | + for (String topic : topics) { |
| 627 | + futures.add(pulsar().getNamespaceService() |
| 628 | + .getBundleAsync(TopicName.get(topic)) |
| 629 | + .thenCompose(topicBundle -> { |
| 630 | + if (bundle.equals(topicBundle)) { |
| 631 | + throw new RestException(Status.CONFLICT, |
| 632 | + "Cannot delete non empty bundle"); |
| 633 | + } |
| 634 | + return CompletableFuture.completedFuture(null); |
| 635 | + })); |
688 | 636 |
|
689 |
| - try { |
690 |
| - NamespaceBundle bundle = validateNamespaceBundleOwnership(namespaceName, policies.bundles, bundleRange, |
691 |
| - authoritative, true); |
692 |
| - // directly remove from owned namespace map and ephemeral node from ZK |
693 |
| - pulsar().getNamespaceService().removeOwnedServiceUnit(bundle); |
694 |
| - } catch (WebApplicationException wae) { |
695 |
| - throw wae; |
696 |
| - } catch (Exception e) { |
697 |
| - log.error("[{}] Failed to remove namespace bundle {}/{}", clientAppId(), namespaceName.toString(), |
698 |
| - bundleRange, e); |
699 |
| - throw new RestException(e); |
700 |
| - } |
| 637 | + } |
| 638 | + deleteTopicsFuture = FutureUtil.waitForAll(futures); |
| 639 | + } |
| 640 | + return deleteTopicsFuture.thenCompose( |
| 641 | + ___ -> pulsar().getNamespaceService().removeOwnedServiceUnitAsync(bundle)); |
| 642 | + }); |
| 643 | + }); |
| 644 | + }); |
701 | 645 | }
|
702 | 646 |
|
703 | 647 | protected CompletableFuture<Void> internalGrantPermissionOnNamespaceAsync(String role, Set<AuthAction> actions) {
|
|
0 commit comments