Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ Please note that the resources are deleted instantly and cannot be recovered onc
with the resource is permanently lost.

```console
Usage: kafkactl delete [-hv] [--dry-run] [--force] [-n=<optionalNamespace>] ([<resourceType> <name> [-V[=<version>]]] | [[-f=<file>] [-R]])
Usage: kafkactl delete [-hv] [--dry-run] [--force] [--cascade] [-n=<optionalNamespace>] ([<resourceType> <name> [-V[=<version>]]] | [[-f=<file>] [-R]])
Description: Delete a resource.

Parameters:
Expand All @@ -598,6 +598,7 @@ Parameters:
Options:
-c, --context=<optionalContext>
Override context defined in config.
--cascade Cascade delete related connectors from Ns4Kafka. Only for connect cluster.
--dry-run Does not persist resources. Validate only.
--execute This option is mandatory to delete resources with wildcard.
-f, --file=<file> YAML file or directory containing resources to delete.
Expand All @@ -619,6 +620,8 @@ kafkactl delete -f resource.yml
kafkactl delete topic myTopic
kafkactl delete connector myConnector --force
kafkactl delete connect-cluster myConnectCluster --force
kafkactl delete connect-cluster myConnectCluster --cascade
kafkactl delete connect-cluster myConnectCluster --cascade --force
kafkactl delete topic *-test
kafkactl delete schema *
kafkactl delete schema mySchema -V latest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package com.michelin.kafkactl.client;

import com.michelin.kafkactl.model.Resource;
import com.michelin.kafkactl.model.request.DeleteResourceRequest;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Body;
Expand All @@ -27,6 +28,7 @@
import io.micronaut.http.annotation.Header;
import io.micronaut.http.annotation.Post;
import io.micronaut.http.annotation.QueryValue;
import io.micronaut.http.annotation.RequestBean;
import io.micronaut.http.client.annotation.Client;
import io.micronaut.http.client.exceptions.ReadTimeoutException;
import io.micronaut.retry.annotation.Retryable;
Expand All @@ -39,28 +41,16 @@ public interface NamespacedResourceClient {
/**
* Delete a given resource.
*
* @param namespace The namespace
* @param kind The kind of resource
* @param name The name of the resource
* @param token The auth token
* @param version The version of the resource, for schemas only.
* @param dryrun Is dry-run mode or not?
* @param request The delete resource request
* @return The delete response
*/
@Delete("{namespace}/{kind}{?name,version,dryrun,force}")
@Delete("{namespace}/{kind}{?name,version,dryrun,force,cascade}")
@Retryable(
delay = "${kafkactl.retry.delay}",
attempts = "${kafkactl.retry.attempt}",
multiplier = "${kafkactl.retry.multiplier}",
includes = ReadTimeoutException.class)
HttpResponse<List<Resource>> delete(
String namespace,
String kind,
@Header("Authorization") String token,
@QueryValue String name,
@Nullable @QueryValue String version,
@QueryValue boolean dryrun,
@QueryValue boolean force);
HttpResponse<List<Resource>> delete(@RequestBean DeleteResourceRequest request);

/**
* Apply a given resource.
Expand Down
36 changes: 24 additions & 12 deletions src/main/java/com/michelin/kafkactl/command/Delete.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.michelin.kafkactl.hook.DryRunHook;
import com.michelin.kafkactl.model.ApiResource;
import com.michelin.kafkactl.model.Resource;
import com.michelin.kafkactl.model.request.DeleteResourceRequest;
import com.michelin.kafkactl.service.FileService;
import com.michelin.kafkactl.service.FormatService;
import com.michelin.kafkactl.service.ResourceService;
Expand Down Expand Up @@ -71,6 +72,11 @@ public class Delete extends DryRunHook {
description = "Force delete resource from Ns4Kafka. Only for connector and connect cluster.")
public boolean force;

@Option(
names = {"--cascade"},
description = "Cascade delete related connectors from Ns4Kafka. Only for connect cluster.")
public boolean cascade;

/**
* Run the "delete" command.
*
Expand Down Expand Up @@ -101,26 +107,32 @@ public Integer onAuthSuccess() {

// Process each document individually, return 0 when all succeed
int errors = resources.stream()
.map(resource -> {
.mapToInt(resource -> {
ApiResource apiResource = apiResourcesService
.getResourceDefinitionByKind(resource.getKind())
.orElseThrow();
Map<String, Object> spec = resource.getSpec();
String version = spec != null && spec.containsKey(VERSION)
? spec.get(VERSION).toString()
: null;
return resourceService.delete(
apiResource,
namespace,
resource.getMetadata().getName(),
(spec != null && spec.containsKey(VERSION)
? spec.get(VERSION).toString()
: null),
dryRun,
force,
commandSpec);
apiResource,
new DeleteResourceRequest(
namespace,
apiResource.getPath(),
null,
resource.getMetadata().getName(),
version,
dryRun,
force,
cascade),
commandSpec)
? 0
: 1;
})
.mapToInt(value -> value ? 0 : 1)
.sum();

return errors > 0 ? 1 : 0;
return errors == 0 ? 0 : 1;
} catch (HttpClientResponseException e) {
formatService.displayError(e, commandSpec);
return 1;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.michelin.kafkactl.model.request;

import io.micronaut.core.annotation.Introspected;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.http.annotation.Header;
import io.micronaut.http.annotation.PathVariable;
import io.micronaut.http.annotation.QueryValue;

/** Delete resource request. */
@Introspected
public record DeleteResourceRequest(
@PathVariable String namespace,
@PathVariable String kind,
@Nullable @Header("Authorization") String token,
@QueryValue String name,
@Nullable @QueryValue String version,
@QueryValue boolean dryrun,
@QueryValue boolean force,
@QueryValue boolean cascade) {
public DeleteResourceRequest withToken(String token) {
return new DeleteResourceRequest(namespace, kind, token, name, version, dryrun, force, cascade);
}
}
32 changes: 9 additions & 23 deletions src/main/java/com/michelin/kafkactl/service/ResourceService.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.michelin.kafkactl.model.Output;
import com.michelin.kafkactl.model.Resource;
import com.michelin.kafkactl.model.SubjectCompatibility;
import com.michelin.kafkactl.model.request.DeleteResourceRequest;
import io.confluent.kafka.schemaregistry.avro.AvroSchema;
import io.confluent.kafka.schemaregistry.client.rest.entities.SchemaReference;
import io.micronaut.core.annotation.Nullable;
Expand Down Expand Up @@ -242,32 +243,17 @@ public HttpResponse<Resource> apply(
* Delete a given resource.
*
* @param apiResource The resource type
* @param namespace The namespace
* @param name The resource name or wildcard
* @param version The version of the resource, for schemas only
* @param dryRun Is dry run mode or not?
* @param request The delete resource request
* @param commandSpec The command that triggered the action
* @return true if deletion succeeded, false otherwise
*/
public boolean delete(
ApiResource apiResource,
String namespace,
String name,
@Nullable String version,
boolean dryRun,
boolean force,
CommandSpec commandSpec) {
public boolean delete(ApiResource apiResource, DeleteResourceRequest request, CommandSpec commandSpec) {
try {
DeleteResourceRequest authorizedRequest = request.withToken(loginService.getAuthorization());
HttpResponse<List<Resource>> response = apiResource.isNamespaced()
? namespacedClient.delete(
namespace,
apiResource.getPath(),
loginService.getAuthorization(),
name,
version,
dryRun,
force)
: nonNamespacedClient.delete(loginService.getAuthorization(), apiResource.getPath(), name, dryRun);
? namespacedClient.delete(authorizedRequest)
: nonNamespacedClient.delete(
loginService.getAuthorization(), apiResource.getPath(), request.name(), request.dryrun());

// Micronaut does not throw exception on 404, so produce a 404 manually
if (response.getStatus().equals(HttpStatus.NOT_FOUND)) {
Expand All @@ -282,11 +268,11 @@ public boolean delete(
.commandLine()
.getOut()
.println(formatService.prettifyKind(apiResource.getKind()) + " \"" + resourceName + "\""
+ (version != null ? " version " + version : "") + " deleted."));
+ (request.version() != null ? " version " + request.version() : "") + " deleted."));

return true;
} catch (HttpClientResponseException exception) {
formatService.displayError(exception, apiResource.getKind(), name, commandSpec);
formatService.displayError(exception, apiResource.getKind(), request.name(), commandSpec);
return false;
}
}
Expand Down
Loading
Loading