Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 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
3 changes: 2 additions & 1 deletion cmd/nerdctl/namespace/namespace_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ func updateCommand() *cobra.Command {
SilenceUsage: true,
SilenceErrors: true,
}
cmd.Flags().StringArrayP("label", "l", nil, "Set labels for a namespace")
cmd.Flags().StringArrayP("label", "l", nil, "Set labels for a namespace (required)")
cmd.MarkFlagRequired("label")
return cmd
}

Expand Down
23 changes: 22 additions & 1 deletion pkg/cmd/namespace/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,15 @@

package namespace

import "strings"
import (
"context"
"fmt"
"slices"
"strings"

"github.com/containerd/containerd/v2/pkg/namespaces"
"github.com/containerd/errdefs"
)

func objectWithLabelArgs(args []string) map[string]string {
if len(args) >= 1 {
Expand All @@ -39,3 +47,16 @@ func labelArgs(labelStrings []string) map[string]string {

return labels
}

// namespaceExists checks if the namespace exists
func namespaceExists(ctx context.Context, store namespaces.Store, namespace string) error {
nsList, err := store.List(ctx)
if err != nil {
return err
}
if slices.Contains(nsList, namespace) {
return nil
}

return fmt.Errorf("namespace %s: %w", namespace, errdefs.ErrNotFound)
}
120 changes: 113 additions & 7 deletions pkg/cmd/namespace/inspect.go
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change will make inspect slower, no?

Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,134 @@ package namespace

import (
"context"
"errors"
"strings"

containerd "github.com/containerd/containerd/v2/client"
"github.com/containerd/containerd/v2/pkg/namespaces"
"github.com/containerd/log"

"github.com/containerd/nerdctl/v2/pkg/api/types"
"github.com/containerd/nerdctl/v2/pkg/clientutil"
"github.com/containerd/nerdctl/v2/pkg/formatter"
"github.com/containerd/nerdctl/v2/pkg/inspecttypes/native"
"github.com/containerd/nerdctl/v2/pkg/mountutil/volumestore"
)

func Inspect(ctx context.Context, client *containerd.Client, inspectedNamespaces []string, options types.NamespaceInspectOptions) error {
result := make([]interface{}, len(inspectedNamespaces))
for index, ns := range inspectedNamespaces {
result := []interface{}{}

warns := []error{}
for _, ns := range inspectedNamespaces {
ctx = namespaces.WithNamespace(ctx, ns)
labels, err := client.NamespaceService().Labels(ctx, ns)
namespaceService := client.NamespaceService()
if err := namespaceExists(ctx, namespaceService, ns); err != nil {
warns = append(warns, err)
continue
}

labels, err := namespaceService.Labels(ctx, ns)
if err != nil {
return err
}

containerInfo, err := containerInfo(ctx, client)
if err != nil {
warns = append(warns, err)
}

imageInfo, err := imageInfo(ctx, client)
if err != nil {
warns = append(warns, err)
}

volumeInfo, err := volumeInfo(ns, options)
if err != nil {
warns = append(warns, err)
}

nsInspect := native.Namespace{
Name: ns,
Labels: &labels,
Name: ns,
Labels: &labels,
Containers: &containerInfo,
Images: &imageInfo,
Volumes: &volumeInfo,
}
result[index] = nsInspect
result = append(result, nsInspect)
}
if err := formatter.FormatSlice(options.Format, options.Stdout, result); err != nil {
return err
}
for _, warn := range warns {
log.G(ctx).Warn(warn)
}

if len(warns) != 0 {
return errors.New("some namespaces could not be inspected")
}
return formatter.FormatSlice(options.Format, options.Stdout, result)

return nil
}
func containerInfo(ctx context.Context, client *containerd.Client) (native.ContainerInfo, error) {
info := native.ContainerInfo{}
containers, err := client.Containers(ctx)
if err != nil {
return info, err
}

info.Count = len(containers)
ids := make([]string, info.Count)

info.IDs = ids
for idx, container := range containers {
ids[idx] = container.ID()
}

return info, nil
}
func imageInfo(ctx context.Context, client *containerd.Client) (native.ImageInfo, error) {
info := native.ImageInfo{}
imageService := client.ImageService()
images, err := imageService.List(ctx)
if err != nil {
return info, err
}

info.Count = len(images)
ids := make([]string, info.Count)

info.IDs = ids
for idx, img := range images {
ids[idx] = strings.Split(img.Target.Digest.String(), ":")[1]
}

return info, nil
}

func volumeInfo(namespace string, options types.NamespaceInspectOptions) (native.VolumeInfo, error) {
info := native.VolumeInfo{}

dataStore, err := clientutil.DataStore(options.GOptions.DataRoot, options.GOptions.Address)
if err != nil {
return info, err
}
volStore, err := volumestore.New(dataStore, namespace)
if err != nil {
return info, err
}

volumes, err := volStore.List(false)
if err != nil {
return info, err
}

info.Count = len(volumes)
names := make([]string, 0, info.Count)

for _, v := range volumes {
names = append(names, v.Name)
}

info.Names = names
return info, nil
}
4 changes: 4 additions & 0 deletions pkg/cmd/namespace/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ import (
func Update(ctx context.Context, client *containerd.Client, namespace string, options types.NamespaceUpdateOptions) error {
labelsArg := objectWithLabelArgs(options.Labels)
namespaces := client.NamespaceService()
if err := namespaceExists(ctx, namespaces, namespace); err != nil {
return err
}

for k, v := range labelsArg {
if err := namespaces.SetLabel(ctx, namespace, k, v); err != nil {
return err
Expand Down
19 changes: 19 additions & 0 deletions pkg/inspecttypes/native/namespace.go
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why include IDs?

Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,23 @@ package native
type Namespace struct {
Name string `json:"Name"`
Labels *map[string]string `json:"Labels,omitempty"`

Containers *ContainerInfo `json:"Containers"`
Images *ImageInfo `json:"Images"`
Volumes *VolumeInfo `json:"Volumes"`
}

type ContainerInfo struct {
Count int `json:"count"`
IDs []string `json:"ids"`
}

type ImageInfo struct {
Count int `json:"count"`
IDs []string `json:"ids"`
}

type VolumeInfo struct {
Count int `json:"count"`
Names []string `json:"names"`
}
Loading