mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
runsc: Support abbreviated container IDs.
Just a UI/usability addition. It's a lot easier to type "60" than "60185c721d7e10c00489f1fa210ee0d35c594873d6376b457fb1815e4fdbfc2c". PiperOrigin-RevId: 199547932 Change-Id: I19011b5061a88aba48a9ad7f8cf954a6782de854
This commit is contained in:
committed by
Shentubot
parent
79fef54eb1
commit
206e90d057
@@ -31,11 +31,11 @@ func TestNotFound(t *testing.T) {
|
||||
|
||||
d := Delete{}
|
||||
if err := d.execute(ids, conf); err == nil {
|
||||
t.Error("Deleting non-existend container should have failed")
|
||||
t.Error("Deleting non-existent container should have failed")
|
||||
}
|
||||
|
||||
d = Delete{force: true}
|
||||
if err := d.execute(ids, conf); err != nil {
|
||||
t.Errorf("Deleting non-existend container with --force should NOT have failed: %v", err)
|
||||
t.Errorf("Deleting non-existent container with --force should NOT have failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@@ -92,14 +93,22 @@ type Container struct {
|
||||
Sandbox *sandbox.Sandbox `json:"sandbox"`
|
||||
}
|
||||
|
||||
// Load loads a container with the given id from a metadata file.
|
||||
// Load loads a container with the given id from a metadata file. id may be an
|
||||
// abbreviation of the full container id, in which case Load loads the
|
||||
// container to which id unambiguously refers to.
|
||||
// Returns ErrNotExist if container doesn't exits.
|
||||
func Load(rootDir, id string) (*Container, error) {
|
||||
log.Debugf("Load container %q %q", rootDir, id)
|
||||
if err := validateID(id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
metaFile := filepath.Join(rootDir, id, metadataFilename)
|
||||
|
||||
cRoot, err := findContainerRoot(rootDir, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
metaFile := filepath.Join(cRoot, metadataFilename)
|
||||
metaBytes, err := ioutil.ReadFile(metaFile)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
@@ -133,6 +142,36 @@ func Load(rootDir, id string) (*Container, error) {
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
func findContainerRoot(rootDir, partialID string) (string, error) {
|
||||
// Check whether the id fully specifies an existing container.
|
||||
cRoot := filepath.Join(rootDir, partialID)
|
||||
if _, err := os.Stat(cRoot); err == nil {
|
||||
return cRoot, nil
|
||||
}
|
||||
|
||||
// Now see whether id could be an abbreviation of exactly 1 of the
|
||||
// container ids. If id is ambigious (it could match more than 1
|
||||
// container), it is an error.
|
||||
cRoot = ""
|
||||
ids, err := List(rootDir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, id := range ids {
|
||||
if strings.HasPrefix(id, partialID) {
|
||||
if cRoot != "" {
|
||||
return "", fmt.Errorf("id %q is ambiguous and could refer to multiple containers: %q, %q", partialID, cRoot, id)
|
||||
}
|
||||
cRoot = id
|
||||
}
|
||||
}
|
||||
if cRoot == "" {
|
||||
return "", os.ErrNotExist
|
||||
}
|
||||
log.Debugf("abbreviated id %q resolves to full id %q", partialID, cRoot)
|
||||
return filepath.Join(rootDir, cRoot), nil
|
||||
}
|
||||
|
||||
// List returns all container ids in the given root directory.
|
||||
func List(rootDir string) ([]string, error) {
|
||||
log.Debugf("List containers %q", rootDir)
|
||||
|
||||
@@ -634,7 +634,7 @@ func TestRunNonRoot(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestMountNewDir check that runsc will create destination directory if it
|
||||
// TestMountNewDir checks that runsc will create destination directory if it
|
||||
// doesn't exit.
|
||||
func TestMountNewDir(t *testing.T) {
|
||||
srcDir := path.Join(os.TempDir(), "src", "newdir", "anotherdir")
|
||||
@@ -660,3 +660,60 @@ func TestMountNewDir(t *testing.T) {
|
||||
t.Fatalf("error running sadbox: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestAbbreviatedIDs checks that runsc supports using abbreviated container
|
||||
// IDs in place of full IDs.
|
||||
func TestAbbreviatedIDs(t *testing.T) {
|
||||
cids := []string{
|
||||
"foo-" + testutil.UniqueContainerID(),
|
||||
"bar-" + testutil.UniqueContainerID(),
|
||||
"baz-" + testutil.UniqueContainerID(),
|
||||
}
|
||||
|
||||
rootDir, err := testutil.SetupRootDir()
|
||||
if err != nil {
|
||||
t.Fatalf("error creating root dir: %v", err)
|
||||
}
|
||||
for _, cid := range cids {
|
||||
spec := testutil.NewSpecWithArgs("sleep", "100")
|
||||
bundleDir, conf, err := testutil.SetupContainerInRoot(rootDir, spec)
|
||||
if err != nil {
|
||||
t.Fatalf("error setting up container: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(rootDir)
|
||||
defer os.RemoveAll(bundleDir)
|
||||
|
||||
// Create and start the container.
|
||||
cont, err := container.Create(cid, spec, conf, bundleDir, "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("error creating container: %v", err)
|
||||
}
|
||||
defer cont.Destroy()
|
||||
}
|
||||
|
||||
// These should all be unambigious.
|
||||
unambiguous := map[string]string{
|
||||
"f": cids[0],
|
||||
cids[0]: cids[0],
|
||||
"bar": cids[1],
|
||||
cids[1]: cids[1],
|
||||
"baz": cids[2],
|
||||
cids[2]: cids[2],
|
||||
}
|
||||
for shortid, longid := range unambiguous {
|
||||
if _, err := container.Load(rootDir, shortid); err != nil {
|
||||
t.Errorf("%q should resolve to %q: %v", shortid, longid, err)
|
||||
}
|
||||
}
|
||||
|
||||
// These should be ambiguous.
|
||||
ambiguous := []string{
|
||||
"b",
|
||||
"ba",
|
||||
}
|
||||
for _, shortid := range ambiguous {
|
||||
if s, err := container.Load(rootDir, shortid); err == nil {
|
||||
t.Errorf("%q should be ambiguous, but resolved to %q", shortid, s.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,21 +84,36 @@ func NewSpecWithArgs(args ...string) *specs.Spec {
|
||||
return spec
|
||||
}
|
||||
|
||||
// SetupRootDir creates a root directory for containers.
|
||||
func SetupRootDir() (string, error) {
|
||||
rootDir, err := ioutil.TempDir("", "containers")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error creating root dir: %v", err)
|
||||
}
|
||||
return rootDir, nil
|
||||
}
|
||||
|
||||
// SetupContainer creates a bundle and root dir for the container, generates a
|
||||
// test config, and writes the spec to config.json in the bundle dir.
|
||||
func SetupContainer(spec *specs.Spec) (rootDir, bundleDir string, conf *boot.Config, err error) {
|
||||
rootDir, err = ioutil.TempDir("", "containers")
|
||||
rootDir, err = SetupRootDir()
|
||||
if err != nil {
|
||||
return "", "", nil, fmt.Errorf("error creating root dir: %v", err)
|
||||
return "", "", nil, err
|
||||
}
|
||||
bundleDir, conf, err = SetupContainerInRoot(rootDir, spec)
|
||||
return rootDir, bundleDir, conf, err
|
||||
}
|
||||
|
||||
// SetupContainerInRoot creates a bundle for the container, generates a test
|
||||
// config, and writes the spec to config.json in the bundle dir.
|
||||
func SetupContainerInRoot(rootDir string, spec *specs.Spec) (bundleDir string, conf *boot.Config, err error) {
|
||||
bundleDir, err = ioutil.TempDir("", "bundle")
|
||||
if err != nil {
|
||||
return "", "", nil, fmt.Errorf("error creating bundle dir: %v", err)
|
||||
return "", nil, fmt.Errorf("error creating bundle dir: %v", err)
|
||||
}
|
||||
|
||||
if err = writeSpec(bundleDir, spec); err != nil {
|
||||
return "", "", nil, fmt.Errorf("error writing spec: %v", err)
|
||||
return "", nil, fmt.Errorf("error writing spec: %v", err)
|
||||
}
|
||||
|
||||
conf = &boot.Config{
|
||||
@@ -110,7 +125,7 @@ func SetupContainer(spec *specs.Spec) (rootDir, bundleDir string, conf *boot.Con
|
||||
TestModeNoFlags: true,
|
||||
}
|
||||
|
||||
return rootDir, bundleDir, conf, nil
|
||||
return bundleDir, conf, nil
|
||||
}
|
||||
|
||||
// writeSpec writes the spec to disk in the given directory.
|
||||
|
||||
Reference in New Issue
Block a user