Skip to content
This repository was archived by the owner on Apr 17, 2025. It is now read-only.

Commit 854e022

Browse files
authored
Merge pull request #311 from superbrothers/hns-delete
kubectl-hns: Add "delete" command
2 parents b6a81a7 + fa81eb4 commit 854e022

File tree

5 files changed

+115
-0
lines changed

5 files changed

+115
-0
lines changed

docs/user-guide/how-to.md

+6
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,12 @@ Instead, you must delete its anchor (note that `subns` is a short form of
236236
$ kubectl delete subns child -n parent
237237
```
238238

239+
You can also use the `kubectl-hns` plugin to delete subnamespaces.
240+
241+
```
242+
$ kubectl hns delete child -n parent
243+
```
244+
239245
This _seems_ to imply that if you delete a _parent_ namespace, all its
240246
subnamespace children (and their descendants) will be deleted as well, since all
241247
objects in a namespace (such as anchors) are deleted along with the namespace.

docs/user-guide/quickstart.md

+11
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,11 @@ kubectl delete subns service-3 -n team-a
614614
Note that `subns` is a short form for `subnamespaceanchor` or
615615
`subnamespaceanchor.hnc.x-k8s.io`.
616616

617+
You can also use the `kubectl-hns` plugin to delete subnamespaces.
618+
619+
```bash
620+
kubectl hns delete service-3 -n team-a
621+
```
617622

618623
Now try to delete `service-1` in the same way, but you'll see it doesn't work:
619624

@@ -674,6 +679,12 @@ team-a
674679
[s] indicates subnamespaces
675680
```
676681

682+
You can also do the above steps in one command run with the `kubectl-hns` plugin:
683+
684+
```bash
685+
kubectl hns delete service-1 -n team-a --allowCascadingDeletion
686+
```
687+
677688
There's an important difference between subnamespaces and regular child
678689
namespace, also known as a full namespace. A subnamespace is created by HNC due
679690
to an anchor being created in the parent; when that anchor is deleted, the

internal/kubectl/delete.go

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
*/
15+
16+
package kubectl
17+
18+
import (
19+
"fmt"
20+
"os"
21+
22+
"github.com/spf13/cobra"
23+
)
24+
25+
var deleteCmd = &cobra.Command{
26+
Use: "delete -n PARENT CHILD",
27+
Short: "Deletes a subnamespace under the given parent.",
28+
Example: `# Delete the 'foo' anchor in the parent 'bar' namespace
29+
kubectl hns delete foo -n bar
30+
31+
# Allow 'foo' to be cascading deleted and delete it
32+
kubectl hns delete foo -n bar --allowCascadingDeletion`,
33+
Args: cobra.ExactArgs(1),
34+
Run: func(cmd *cobra.Command, args []string) {
35+
nnm := args[0]
36+
37+
parent, _ := cmd.Flags().GetString("namespace")
38+
if parent == "" {
39+
fmt.Println("Error: parent must be set via --namespace or -n")
40+
os.Exit(1)
41+
}
42+
43+
allowCD, _ := cmd.Flags().GetBool("allowCascadingDeletion")
44+
if allowCD {
45+
hc := client.getHierarchy(nnm)
46+
if hc.Spec.AllowCascadingDeletion {
47+
fmt.Printf("Cascading deletion for '%s' is already set to 'true'; unchanged\n", nnm)
48+
} else {
49+
fmt.Printf("Allowing cascading deletion on '%s'\n", nnm)
50+
hc.Spec.AllowCascadingDeletion = true
51+
client.updateHierarchy(hc, fmt.Sprintf("update the hierarchical configuration of %s", nnm))
52+
}
53+
}
54+
55+
client.deleteAnchor(parent, nnm)
56+
},
57+
}
58+
59+
func newDeleteCmd() *cobra.Command {
60+
deleteCmd.Flags().StringP("namespace", "n", "", "The parent namespace for the new subnamespace")
61+
deleteCmd.Flags().BoolP("allowCascadingDeletion", "a", false, "Allows cascading deletion of its subnamespaces.")
62+
return deleteCmd
63+
}

internal/kubectl/root.go

+14
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ type Client interface {
4949
getHierarchy(nnm string) *api.HierarchyConfiguration
5050
updateHierarchy(hier *api.HierarchyConfiguration, reason string)
5151
createAnchor(nnm string, hnnm string)
52+
deleteAnchor(nnm string, hnnm string)
5253
getAnchorStatus(nnm string) anchorStatus
5354
getHNCConfig() *api.HNCConfiguration
5455
updateHNCConfig(*api.HNCConfiguration)
@@ -102,6 +103,7 @@ func init() {
102103
rootCmd.AddCommand(newDescribeCmd())
103104
rootCmd.AddCommand(newTreeCmd())
104105
rootCmd.AddCommand(newCreateCmd())
106+
rootCmd.AddCommand(newDeleteCmd())
105107
rootCmd.AddCommand(newConfigCmd())
106108
rootCmd.AddCommand(newVersionCmd())
107109
rootCmd.AddCommand(newHrqCmd())
@@ -186,6 +188,18 @@ func (cl *realClient) createAnchor(nnm string, hnnm string) {
186188
fmt.Printf("Successfully created %q subnamespace anchor in %q namespace\n", hnnm, nnm)
187189
}
188190

191+
func (cl *realClient) deleteAnchor(nnm string, hnnm string) {
192+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
193+
defer cancel()
194+
195+
err := hncClient.Delete().Resource(api.Anchors).Namespace(nnm).Name(hnnm).Do(ctx).Error()
196+
if err != nil {
197+
fmt.Printf("\nCould not delete subnamespace anchor.\nReason: %s\n", err)
198+
os.Exit(1)
199+
}
200+
fmt.Printf("Successfully deleted %q subnamespace anchor in %q namespace\n", hnnm, nnm)
201+
}
202+
189203
func (cl *realClient) getHNCConfig() *api.HNCConfiguration {
190204
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
191205
defer cancel()

test/e2e/quickstart_test.go

+21
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,12 @@ spec:
253253
// show how to delete a subns correctly
254254
MustNotRun("kubectl delete ns", nsService3)
255255
MustRun("kubectl delete subns", nsService3, "-n", nsTeamA)
256+
257+
// show how to delete a subns correctly with the kubectl-hns plugin
258+
CreateSubnamespace(nsService4, nsTeamA)
259+
MustNotRun("kubectl hns delete", nsService4)
260+
MustRun("kubectl hns delete", nsService4, "-n", nsTeamA)
261+
256262
// This should not run because service-1 contains its own subnamespace that would be deleted with it,
257263
MustNotRun("kubectl delete subns", nsService1, "-n", nsTeamA)
258264

@@ -263,6 +269,21 @@ spec:
263269
"└── [s] " + nsService2
264270
RunShouldContain(expected, defTimeout, "kubectl hns tree", nsTeamA)
265271

272+
// cascading deletion with the kubectl-hns plugin
273+
CreateSubnamespace(nsService1, nsTeamA)
274+
CreateSubnamespace(nsService4, nsService1)
275+
expected = "" +
276+
nsService1 + "\n" +
277+
"└── [s] " + nsService4
278+
RunShouldContain(expected, defTimeout, "kubectl hns tree", nsService1, "-n", nsTeamA)
279+
MustNotRun("kubectl hns delete", nsService1, "-n", nsTeamA)
280+
MustRun("kubectl hns delete", nsService1, "-n", nsTeamA, "--allowCascadingDeletion")
281+
expected = "" +
282+
nsTeamA + "\n" +
283+
"└── [s] " + nsService2
284+
// cascading deletion of its subnamespaces takes time
285+
RunShouldContain(expected, cleanupTimeout, "kubectl hns tree", nsTeamA)
286+
266287
// Show the difference of a subns and regular child ns
267288
CreateSubnamespace(nsService4, nsTeamA)
268289
expected = "" +

0 commit comments

Comments
 (0)