From 844c58102e437cf6c4a33bcc03961ae9071dba2b Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 1 Jul 2019 14:48:48 -0400 Subject: [PATCH] Add cgroup delete opt for ns deletion Closes #3305 This adds an opt and a `--cgroup,-c` flag to `ctr namespaces rm` to remove the cgroup that is commonly created with runtimes. Signed-off-by: Michael Crosby --- cmd/ctr/commands/namespaces/namespaces.go | 10 +++++- .../commands/namespaces/namespaces_linux.go | 31 ++++++++++++++++ .../commands/namespaces/namespaces_other.go | 28 +++++++++++++++ metadata/namespaces.go | 10 +++++- namespaces.go | 16 ++++++--- namespaces/store.go | 11 +++++- namespaces_opts_linux.go | 36 +++++++++++++++++++ 7 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 cmd/ctr/commands/namespaces/namespaces_linux.go create mode 100644 cmd/ctr/commands/namespaces/namespaces_other.go create mode 100644 namespaces_opts_linux.go diff --git a/cmd/ctr/commands/namespaces/namespaces.go b/cmd/ctr/commands/namespaces/namespaces.go index 16c95d7f4..81ce3dc0a 100644 --- a/cmd/ctr/commands/namespaces/namespaces.go +++ b/cmd/ctr/commands/namespaces/namespaces.go @@ -146,6 +146,12 @@ var removeCommand = cli.Command{ Usage: "remove one or more namespaces", ArgsUsage: " [, ...]", Description: "remove one or more namespaces. for now, the namespace must be empty", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "cgroup,c", + Usage: "delete the namespace's cgroup", + }, + }, Action: func(context *cli.Context) error { var exitErr error client, ctx, cancel, err := commands.NewClient(context) @@ -153,9 +159,11 @@ var removeCommand = cli.Command{ return err } defer cancel() + + opts := deleteOpts(context) namespaces := client.NamespaceService() for _, target := range context.Args() { - if err := namespaces.Delete(ctx, target); err != nil { + if err := namespaces.Delete(ctx, target, opts...); err != nil { if !errdefs.IsNotFound(err) { if exitErr == nil { exitErr = errors.Wrapf(err, "unable to delete %v", target) diff --git a/cmd/ctr/commands/namespaces/namespaces_linux.go b/cmd/ctr/commands/namespaces/namespaces_linux.go new file mode 100644 index 000000000..0300bb103 --- /dev/null +++ b/cmd/ctr/commands/namespaces/namespaces_linux.go @@ -0,0 +1,31 @@ +/* + Copyright The containerd Authors. + + Licensed 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 namespaces + +import ( + "github.com/containerd/containerd" + "github.com/containerd/containerd/namespaces" + "github.com/urfave/cli" +) + +func deleteOpts(context *cli.Context) []namespaces.DeleteOpts { + var opts []namespaces.DeleteOpts + if context.Bool("cgroup") { + opts = append(opts, containerd.WithNamespaceCgroupDeletion) + } + return opts +} diff --git a/cmd/ctr/commands/namespaces/namespaces_other.go b/cmd/ctr/commands/namespaces/namespaces_other.go new file mode 100644 index 000000000..b0f12e5d9 --- /dev/null +++ b/cmd/ctr/commands/namespaces/namespaces_other.go @@ -0,0 +1,28 @@ +// +build !linux + +/* + Copyright The containerd Authors. + + Licensed 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 namespaces + +import ( + "github.com/containerd/containerd/namespaces" + "github.com/urfave/cli" +) + +func deleteOpts(context *cli.Context) []namespaces.DeleteOpts { + return nil +} diff --git a/metadata/namespaces.go b/metadata/namespaces.go index 74951eb5c..25d0e1578 100644 --- a/metadata/namespaces.go +++ b/metadata/namespaces.go @@ -129,7 +129,15 @@ func (s *namespaceStore) List(ctx context.Context) ([]string, error) { return namespaces, nil } -func (s *namespaceStore) Delete(ctx context.Context, namespace string) error { +func (s *namespaceStore) Delete(ctx context.Context, namespace string, opts ...namespaces.DeleteOpts) error { + i := &namespaces.DeleteInfo{ + Name: namespace, + } + for _, o := range opts { + if err := o(ctx, i); err != nil { + return err + } + } bkt := getBucket(s.tx, bucketKeyVersion) if empty, err := s.namespaceEmpty(ctx, namespace); err != nil { return err diff --git a/namespaces.go b/namespaces.go index eea70ca33..4c66406b0 100644 --- a/namespaces.go +++ b/namespaces.go @@ -100,10 +100,18 @@ func (r *remoteNamespaces) List(ctx context.Context) ([]string, error) { return namespaces, nil } -func (r *remoteNamespaces) Delete(ctx context.Context, namespace string) error { - var req api.DeleteNamespaceRequest - - req.Name = namespace +func (r *remoteNamespaces) Delete(ctx context.Context, namespace string, opts ...namespaces.DeleteOpts) error { + i := namespaces.DeleteInfo{ + Name: namespace, + } + for _, o := range opts { + if err := o(ctx, &i); err != nil { + return err + } + } + req := api.DeleteNamespaceRequest{ + Name: namespace, + } _, err := r.client.Delete(ctx, &req) if err != nil { return errdefs.FromGRPC(err) diff --git a/namespaces/store.go b/namespaces/store.go index 0b5c98569..5936772cb 100644 --- a/namespaces/store.go +++ b/namespaces/store.go @@ -33,5 +33,14 @@ type Store interface { List(ctx context.Context) ([]string, error) // Delete removes the namespace. The namespace must be empty to be deleted. - Delete(ctx context.Context, namespace string) error + Delete(ctx context.Context, namespace string, opts ...DeleteOpts) error } + +// DeleteInfo specifies information for the deletion of a namespace +type DeleteInfo struct { + // Name of the namespace + Name string +} + +// DeleteOpts allows the caller to set options for namespace deletion +type DeleteOpts func(context.Context, *DeleteInfo) error diff --git a/namespaces_opts_linux.go b/namespaces_opts_linux.go new file mode 100644 index 000000000..6b8cc8f85 --- /dev/null +++ b/namespaces_opts_linux.go @@ -0,0 +1,36 @@ +/* + Copyright The containerd Authors. + + Licensed 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 containerd + +import ( + "context" + + "github.com/containerd/cgroups" + "github.com/containerd/containerd/namespaces" +) + +// WithNamespaceCgroupDeletion removes the cgroup directory that was created for the namespace +func WithNamespaceCgroupDeletion(ctx context.Context, i *namespaces.DeleteInfo) error { + cg, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(i.Name)) + if err != nil { + if err == cgroups.ErrCgroupDeleted { + return nil + } + return err + } + return cg.Delete() +}