Skip to content

Commit

Permalink
Ensure that SQLite state handles name-ID collisions
Browse files Browse the repository at this point in the history
If a container with an ID starting with "db1" exists, and a
container named "db1" also exists, and they are different
containers - if I run `podman inspect db1` the container named
"db1" should be inspected, and there should not be an error that
multiple containers matched the name or id "db1". This was
already handled by BoltDB, and now is properly managed by SQLite.

Fixes containers#17905

Signed-off-by: Matt Heon <[email protected]>
  • Loading branch information
mheon committed Mar 24, 2023
1 parent f9beb0d commit 7daab31
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 32 deletions.
81 changes: 49 additions & 32 deletions libpod/sqlite_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,26 +487,29 @@ func (s *SQLiteState) LookupContainerID(idOrName string) (string, error) {
return "", define.ErrDBClosed
}

rows, err := s.conn.Query("SELECT ID FROM ContainerConfig WHERE ContainerConfig.Name=? OR (ContainerConfig.ID LIKE ?);", idOrName, idOrName+"%")
rows, err := s.conn.Query("SELECT ID, Name FROM ContainerConfig WHERE ContainerConfig.Name=? OR (ContainerConfig.ID LIKE ?);", idOrName, idOrName+"%")
if err != nil {
return "", fmt.Errorf("looking up container %q in database: %w", idOrName, err)
}
defer rows.Close()

var id string
foundResult := false
var (
id, name string
resCount uint
)
for rows.Next() {
if foundResult {
return "", fmt.Errorf("more than one result for container %q: %w", idOrName, define.ErrCtrExists)
}

if err := rows.Scan(&id); err != nil {
if err := rows.Scan(&id, &name); err != nil {
return "", fmt.Errorf("retrieving container %q ID from database: %w", idOrName, err)
}
foundResult = true
if name == idOrName {
return id, nil
}
resCount++
}
if !foundResult {
if resCount == 0 {
return "", define.ErrNoSuchCtr
} else if resCount > 1 {
return "", fmt.Errorf("more than one result for container %q: %w", idOrName, define.ErrCtrExists)
}

return id, nil
Expand All @@ -523,26 +526,33 @@ func (s *SQLiteState) LookupContainer(idOrName string) (*Container, error) {
return nil, define.ErrDBClosed
}

rows, err := s.conn.Query("SELECT JSON FROM ContainerConfig WHERE ContainerConfig.Name=? OR (ContainerConfig.ID LIKE ?);", idOrName, idOrName+"%")
rows, err := s.conn.Query("SELECT JSON, Name FROM ContainerConfig WHERE ContainerConfig.Name=? OR (ContainerConfig.ID LIKE ?);", idOrName, idOrName+"%")
if err != nil {
return nil, fmt.Errorf("looking up container %q in database: %w", idOrName, err)
}
defer rows.Close()

var rawJSON string
foundResult := false
var (
rawJSON, name string
exactName bool
resCount uint
)
for rows.Next() {
if foundResult {
return nil, fmt.Errorf("more than one result for container %q: %w", idOrName, define.ErrCtrExists)
}

if err := rows.Scan(&rawJSON); err != nil {
if err := rows.Scan(&rawJSON, &name); err != nil {
return nil, fmt.Errorf("retrieving container %q ID from database: %w", idOrName, err)
}
foundResult = true
if name == idOrName {
exactName = true
break
}
resCount++
}
if !foundResult {
return nil, fmt.Errorf("no container with name or ID %q found: %w", idOrName, define.ErrNoSuchCtr)
if !exactName {
if resCount == 0 {
return nil, fmt.Errorf("no container with name or ID %q found: %w", idOrName, define.ErrNoSuchCtr)
} else if resCount > 1 {
return nil, fmt.Errorf("more than one result for container %q: %w", idOrName, define.ErrCtrExists)
}
}

ctr := new(Container)
Expand Down Expand Up @@ -1303,26 +1313,33 @@ func (s *SQLiteState) LookupPod(idOrName string) (*Pod, error) {
return nil, define.ErrDBClosed
}

rows, err := s.conn.Query("SELECT JSON FROM PodConfig WHERE PodConfig.Name=? OR (PodConfig.ID LIKE ?);", idOrName, idOrName+"%")
rows, err := s.conn.Query("SELECT JSON, Name FROM PodConfig WHERE PodConfig.Name=? OR (PodConfig.ID LIKE ?);", idOrName, idOrName+"%")
if err != nil {
return nil, fmt.Errorf("looking up pod %q in database: %w", idOrName, err)
}
defer rows.Close()

var rawJSON string
foundResult := false
var (
rawJSON, name string
exactName bool
resCount uint
)
for rows.Next() {
if foundResult {
return nil, fmt.Errorf("more than one result for pod %q: %w", idOrName, define.ErrCtrExists)
}

if err := rows.Scan(&rawJSON); err != nil {
if err := rows.Scan(&rawJSON, &name); err != nil {
return nil, fmt.Errorf("error retrieving pod %q ID from database: %w", idOrName, err)
}
foundResult = true
if name == idOrName {
exactName = true
break
}
resCount++
}
if !foundResult {
return nil, fmt.Errorf("no pod with name or ID %s found: %w", idOrName, define.ErrNoSuchPod)
if !exactName {
if resCount == 0 {
return nil, fmt.Errorf("no pod with name or ID %s found: %w", idOrName, define.ErrNoSuchPod)
} else if resCount > 1 {
return nil, fmt.Errorf("more than one result for pod %q: %w", idOrName, define.ErrCtrExists)
}
}

return s.createPod(rawJSON)
Expand Down
17 changes: 17 additions & 0 deletions test/e2e/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -718,4 +718,21 @@ var _ = Describe("Podman create", func() {
setup.WaitWithDefaultTimeout()
Expect(setup).Should(Exit(0))
})

It("create container with name subset of existing ID", func() {
create1 := podmanTest.Podman([]string{"create", "-t", ALPINE, "top"})
create1.WaitWithDefaultTimeout()
Expect(create1).Should(Exit(0))
ctr1ID := create1.OutputToString()

ctr2Name := ctr1ID[:5]
create2 := podmanTest.Podman([]string{"create", "-t", "--name", ctr2Name, ALPINE, "top"})
create2.WaitWithDefaultTimeout()
Expect(create2).Should(Exit(0))

inspect := podmanTest.Podman([]string{"inspect", "--format", "{{.Name}}", ctr2Name})
inspect.WaitWithDefaultTimeout()
Expect(inspect).Should(Exit(0))
Expect(inspect.OutputToString()).Should(Equal(ctr2Name))
})
})
16 changes: 16 additions & 0 deletions test/e2e/pod_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1199,4 +1199,20 @@ ENTRYPOINT ["sleep","99999"]
Expect(strings[0]).Should(ContainSubstring("size=10240k"))
})

It("create pod with name subset of existing ID", func() {
create1 := podmanTest.Podman([]string{"pod", "create"})
create1.WaitWithDefaultTimeout()
Expect(create1).Should(Exit(0))
pod1ID := create1.OutputToString()

pod2Name := pod1ID[:5]
create2 := podmanTest.Podman([]string{"pod", "create", pod2Name})
create2.WaitWithDefaultTimeout()
Expect(create2).Should(Exit(0))

inspect := podmanTest.Podman([]string{"pod", "inspect", "--format", "{{.Name}}", pod2Name})
inspect.WaitWithDefaultTimeout()
Expect(inspect).Should(Exit(0))
Expect(inspect.OutputToString()).Should(Equal(pod2Name))
})
})

0 comments on commit 7daab31

Please sign in to comment.