Skip to content

Commit

Permalink
feat: Added delete cascade input
Browse files Browse the repository at this point in the history
Signed-off-by: Steve Hipwell <[email protected]>
  • Loading branch information
stevehipwell authored and alekc committed Aug 21, 2024
1 parent f0d2112 commit abed1de
Show file tree
Hide file tree
Showing 4 changed files with 267 additions and 39 deletions.
20 changes: 9 additions & 11 deletions docs/resources/kubectl_manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ YAML
> Note: When the kind is a Deployment, this provider will wait for the deployment to be rolled out automatically for you!
### With explicit `wait_for`

If `wait_for` is specified, upon applying the resource, provider will wait for **all** conditions to become true before proceeding further.

```hcl
Expand Down Expand Up @@ -88,23 +89,21 @@ YAML
* `validate_schema` - Optional. Setting to `false` will mimic `kubectl apply --validate=false` mode. Default `true`.
* `wait` - Optional. Set this flag to wait or not for finalized to complete for deleted objects. Default `false`.
* `wait_for_rollout` - Optional. Set this flag to wait or not for Deployments and APIService to complete rollout. Default `true`.
* `wait_for`- Optional. If set, will wait until either all conditions are satisfied, or until timeout is reached (see [below for nested schema](#nestedblock--wait_for)). Under the hood [gojsonq](https://github.com/thedevsaddam/gojsonq) is used for querying, see the related syntax and examples
* `wait_for` - Optional. If set, will wait until either all conditions are satisfied, or until timeout is reached (see [below for nested schema](#wait_for)). Under the hood [gojsonq](https://github.com/thedevsaddam/gojsonq) is used for querying, see the related syntax and examples.
* `delete_cascade` - Optional; `Background` or `Foreground` are valid options. If set this overrides the default provider behaviour which is to use `Background` unless `wait` is `true` when `Foreground` will be used. To duplicate the default behaviour of `kubectl` this should be explicitly set to `Background`.

### Nested schemas
<a id="nestedblock--wait_for"></a>
### Nested Schema for `wait_for`
### `wait_for`

Required:

- `field` (Block List, Min: 1) Condition criteria for a field (see [below for nested schema](#nestedblock--wait_for--field))
* `field` (Block List, Min: 1) Condition criteria for a field (see [below for nested schema](#wait_forfield))

<a id="nestedblock--wait_for--field"></a>
### Nested Schema for `wait_for.field`
### `wait_for.field`

Required:

- `key` (String) Key which should be matched from resulting object
- `value` (String) Value to wait for
* `key` (String) Key which should be matched from resulting object
* `value` (String) Value to wait for

Optional:

Expand Down Expand Up @@ -152,7 +151,6 @@ YAML

> Note: Only Map values are supported to be made sensitive. If you need to make a value from a list (or sub-list) sensitive, you can set the high-level key as sensitive to suppress the entire tree output.

## Ignore Manifest Fields

You can configure a list of yaml keys to ignore changes to via the `ignore_fields` field.
Expand Down Expand Up @@ -219,7 +217,7 @@ You can disable this behavior by setting the `wait_for_rollout` field to `false`

This provider supports importing existing resources. The ID format expected uses a double `//` as a deliminator (as apiVersion can have a forward-slash):

```
```shell
# Import the my-namespace Namespace
terraform import kubectl_manifest.my-namespace v1//Namespace//my-namespace

Expand Down
70 changes: 54 additions & 16 deletions kubernetes/resource_kubectl_manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@ import (
"crypto/sha256"
"encoding/base64"
"fmt"
"github.com/sergi/go-diff/diffmatchpatch"
"k8s.io/cli-runtime/pkg/genericiooptions"
k8sdelete "k8s.io/kubectl/pkg/cmd/delete"
"log"
"os"
"regexp"
"sort"
"strings"
"time"

"github.com/sergi/go-diff/diffmatchpatch"
"k8s.io/cli-runtime/pkg/genericiooptions"
k8sdelete "k8s.io/kubectl/pkg/cmd/delete"

"github.com/alekc/terraform-provider-kubectl/flatten"
"github.com/alekc/terraform-provider-kubectl/internal/types"

Expand All @@ -24,7 +25,9 @@ import (
validate2 "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/mitchellh/mapstructure"
"github.com/thedevsaddam/gojsonq/v2"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/kubectl/pkg/scheme"
Expand Down Expand Up @@ -411,7 +414,7 @@ var (
},
"field_manager": {
Type: schema.TypeString,
Description: "Override the default field manager name. This is only relevent when using server-side apply.",
Description: "Override the default field manager name. This is only relevant when using server-side apply.",
Optional: true,
Default: "kubectl",
},
Expand Down Expand Up @@ -487,6 +490,12 @@ var (
},
},
},
"delete_cascade": {
Type: schema.TypeString,
Description: "Cascade mode for delete operations, explicitly setting this to Background to match kubectl is recommended. Default is Background unless wait has been set when it will be Foreground.",
Optional: true,
ValidateDiagFunc: validate2.ToDiagFunc(validate2.StringInSlice([]string{string(meta_v1.DeletePropagationBackground), string(meta_v1.DeletePropagationForeground)}, false)),
},
}
)

Expand Down Expand Up @@ -719,29 +728,58 @@ func resourceKubectlManifestDelete(ctx context.Context, d *schema.ResourceData,

log.Printf("[INFO] %s perform delete of manifest", manifest)

propagationPolicy := meta_v1.DeletePropagationBackground
waitForDelete := d.Get("wait").(bool)
if waitForDelete {

var propagationPolicy meta_v1.DeletionPropagation
cascadeInput := d.Get("delete_cascade").(string)
if len(cascadeInput) > 0 {
propagationPolicy = meta_v1.DeletionPropagation(cascadeInput)
} else if waitForDelete {
propagationPolicy = meta_v1.DeletePropagationForeground
} else {
propagationPolicy = meta_v1.DeletePropagationBackground
}

var resourceVersion string
if waitForDelete {
rawResponse, err := restClient.ResourceInterface.Get(ctx, manifest.GetName(), meta_v1.GetOptions{})
if err != nil {
return err
}

response := yaml.NewFromUnstructured(rawResponse)
resourceVersion = response.GetResourceVersion()
}

err = restClient.ResourceInterface.Delete(ctx, manifest.GetName(), meta_v1.DeleteOptions{PropagationPolicy: &propagationPolicy})
resourceGone := errors.IsGone(err) || errors.IsNotFound(err)
if err != nil && !resourceGone {
return fmt.Errorf("%v failed to delete kubernetes resource: %+v", manifest, err)
}
// at the moment the foreground propagation policy does not behave as expected (it won't block waiting for deletion
// and it's up to us to check that the object has been successfully deleted.
for waitForDelete {
_, err := restClient.ResourceInterface.Get(ctx, manifest.GetName(), meta_v1.GetOptions{})
resourceGone = errors.IsGone(err) || errors.IsNotFound(err)

// The rest client doesn't wait for the delete so we need custom logic
if waitForDelete {
log.Printf("[INFO] %s waiting for delete of manifest to complete", manifest)

watcher, err := restClient.ResourceInterface.Watch(ctx, meta_v1.ListOptions{Watch: true, FieldSelector: fields.OneTermEqualSelector("metadata.name", manifest.GetName()).String(), ResourceVersion: resourceVersion})
if err != nil {
if resourceGone {
break
return err
}

defer watcher.Stop()

deleted := false
for !deleted {
select {
case event := <-watcher.ResultChan():
if event.Type == watch.Deleted {
deleted = true
}

case <-ctx.Done():
return fmt.Errorf("%s failed to delete kubernetes resource", manifest)
}
return fmt.Errorf("%v failed to delete kubernetes resource: %+v", manifest, err)
}
log.Printf("[DEBUG] %v waiting for deletion of the resource:\n%s", manifest, yamlBody)
time.Sleep(time.Second * 10)
}

// Success remove it from state
Expand Down
Loading

0 comments on commit abed1de

Please sign in to comment.