mirror of https://github.com/containers/podman.git
Add backend code for generic dependencies
Signed-off-by: Matthew Heon <matthew.heon@gmail.com> Closes: #577 Approved by: rhatdan
This commit is contained in:
parent
838df4eec4
commit
a1c0f18bca
|
@ -205,6 +205,8 @@ type ContainerConfig struct {
|
|||
// Namespace Config
|
||||
// IDs of container to share namespaces with
|
||||
// NetNsCtr conflicts with the CreateNetNS bool
|
||||
// These containers are considered dependencies of the given container
|
||||
// They must be started before the given container is started
|
||||
IPCNsCtr string `json:"ipcNsCtr,omitempty"`
|
||||
MountNsCtr string `json:"mountNsCtr,omitempty"`
|
||||
NetNsCtr string `json:"netNsCtr,omitempty"`
|
||||
|
@ -213,6 +215,10 @@ type ContainerConfig struct {
|
|||
UTSNsCtr string `json:"utsNsCtr,omitempty"`
|
||||
CgroupNsCtr string `json:"cgroupNsCtr,omitempty"`
|
||||
|
||||
// IDs of dependency containers
|
||||
// These containers must be started before this container is started
|
||||
Dependencies []string
|
||||
|
||||
// Network Config
|
||||
// CreateNetNS indicates that libpod should create and configure a new
|
||||
// network namespace for the container
|
||||
|
@ -363,6 +369,8 @@ func (c *Container) User() string {
|
|||
func (c *Container) Dependencies() []string {
|
||||
// Collect in a map first to remove dupes
|
||||
dependsCtrs := map[string]bool{}
|
||||
|
||||
// First add all namespace containers
|
||||
if c.config.IPCNsCtr != "" {
|
||||
dependsCtrs[c.config.IPCNsCtr] = true
|
||||
}
|
||||
|
@ -385,6 +393,11 @@ func (c *Container) Dependencies() []string {
|
|||
dependsCtrs[c.config.CgroupNsCtr] = true
|
||||
}
|
||||
|
||||
// Add all generic dependencies
|
||||
for _, id := range c.config.Dependencies {
|
||||
dependsCtrs[id] = true
|
||||
}
|
||||
|
||||
if len(dependsCtrs) == 0 {
|
||||
return []string{}
|
||||
}
|
||||
|
|
|
@ -625,6 +625,38 @@ func WithCgroupNSFrom(nsCtr *Container) CtrCreateOption {
|
|||
}
|
||||
}
|
||||
|
||||
// WithDependencies sets dependency containers of the given container
|
||||
// Dependency containers must be running before this container is started
|
||||
func WithDependencyCtrs(ctrs []*Container) CtrCreateOption {
|
||||
return func(ctr *Container) error {
|
||||
if ctr.valid {
|
||||
return ErrCtrFinalized
|
||||
}
|
||||
|
||||
deps := make([]string, 0, len(ctrs))
|
||||
|
||||
for _, dep := range ctrs {
|
||||
if !dep.valid {
|
||||
return errors.Wrapf(ErrCtrRemoved, "container %s is not valid", dep.ID())
|
||||
}
|
||||
|
||||
if dep.ID() == ctr.ID() {
|
||||
return errors.Wrapf(ErrInvalidArg, "must specify another container")
|
||||
}
|
||||
|
||||
if ctr.config.Pod != "" && dep.config.Pod != ctr.config.Pod {
|
||||
return errors.Wrapf(ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, dep.ID())
|
||||
}
|
||||
|
||||
deps = append(deps, dep.ID())
|
||||
}
|
||||
|
||||
ctr.config.Dependencies = deps
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithNetNS indicates that the container should be given a new network
|
||||
// namespace with a minimal configuration
|
||||
// An optional array of port mappings can be provided
|
||||
|
|
|
@ -656,6 +656,83 @@ func TestContainerInUseOneContainerMultipleDependencies(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestContainerInUseGenericDependency(t *testing.T) {
|
||||
runForAllStates(t, func(t *testing.T, state State, lockPath string) {
|
||||
testCtr1, err := getTestCtr1(lockPath)
|
||||
assert.NoError(t, err)
|
||||
testCtr2, err := getTestCtr2(lockPath)
|
||||
assert.NoError(t, err)
|
||||
|
||||
testCtr2.config.Dependencies = []string{testCtr1.config.ID}
|
||||
|
||||
err = state.AddContainer(testCtr1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = state.AddContainer(testCtr2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
ids, err := state.ContainerInUse(testCtr1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(ids))
|
||||
assert.Equal(t, testCtr2.config.ID, ids[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestContainerInUseMultipleGenericDependencies(t *testing.T) {
|
||||
runForAllStates(t, func(t *testing.T, state State, lockPath string) {
|
||||
testCtr1, err := getTestCtr1(lockPath)
|
||||
assert.NoError(t, err)
|
||||
testCtr2, err := getTestCtr2(lockPath)
|
||||
assert.NoError(t, err)
|
||||
testCtr3, err := getTestCtrN("3", lockPath)
|
||||
assert.NoError(t, err)
|
||||
|
||||
testCtr3.config.Dependencies = []string{testCtr1.config.ID, testCtr2.config.ID}
|
||||
|
||||
err = state.AddContainer(testCtr1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = state.AddContainer(testCtr2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = state.AddContainer(testCtr3)
|
||||
assert.NoError(t, err)
|
||||
|
||||
ids1, err := state.ContainerInUse(testCtr1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(ids1))
|
||||
assert.Equal(t, testCtr3.config.ID, ids1[0])
|
||||
|
||||
ids2, err := state.ContainerInUse(testCtr2)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(ids2))
|
||||
assert.Equal(t, testCtr3.config.ID, ids2[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestContainerInUseGenericAndNamespaceDependencies(t *testing.T) {
|
||||
runForAllStates(t, func(t *testing.T, state State, lockPath string) {
|
||||
testCtr1, err := getTestCtr1(lockPath)
|
||||
assert.NoError(t, err)
|
||||
testCtr2, err := getTestCtr2(lockPath)
|
||||
assert.NoError(t, err)
|
||||
|
||||
testCtr2.config.Dependencies = []string{testCtr1.config.ID}
|
||||
testCtr2.config.IPCNsCtr = testCtr1.config.ID
|
||||
|
||||
err = state.AddContainer(testCtr1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = state.AddContainer(testCtr2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
ids, err := state.ContainerInUse(testCtr1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(ids))
|
||||
assert.Equal(t, testCtr2.config.ID, ids[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestCannotRemoveContainerWithDependency(t *testing.T) {
|
||||
runForAllStates(t, func(t *testing.T, state State, lockPath string) {
|
||||
testCtr1, err := getTestCtr1(lockPath)
|
||||
|
@ -680,6 +757,30 @@ func TestCannotRemoveContainerWithDependency(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestCannotRemoveContainerWithGenericDependency(t *testing.T) {
|
||||
runForAllStates(t, func(t *testing.T, state State, lockPath string) {
|
||||
testCtr1, err := getTestCtr1(lockPath)
|
||||
assert.NoError(t, err)
|
||||
testCtr2, err := getTestCtr2(lockPath)
|
||||
assert.NoError(t, err)
|
||||
|
||||
testCtr2.config.Dependencies = []string{testCtr1.config.ID}
|
||||
|
||||
err = state.AddContainer(testCtr1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = state.AddContainer(testCtr2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = state.RemoveContainer(testCtr1)
|
||||
assert.Error(t, err)
|
||||
|
||||
ctrs, err := state.AllContainers()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(ctrs))
|
||||
})
|
||||
}
|
||||
|
||||
func TestCanRemoveContainerAfterDependencyRemoved(t *testing.T) {
|
||||
runForAllStates(t, func(t *testing.T, state State, lockPath string) {
|
||||
testCtr1, err := getTestCtr1(lockPath)
|
||||
|
@ -773,6 +874,22 @@ func TestCannotUseBadIDAsDependency(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestCannotUseBadIDAsGenericDependency(t *testing.T) {
|
||||
runForAllStates(t, func(t *testing.T, state State, lockPath string) {
|
||||
testCtr, err := getTestCtr1(lockPath)
|
||||
assert.NoError(t, err)
|
||||
|
||||
testCtr.config.Dependencies = []string{strings.Repeat("5", 32)}
|
||||
|
||||
err = state.AddContainer(testCtr)
|
||||
assert.Error(t, err)
|
||||
|
||||
ctrs, err := state.AllContainers()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, len(ctrs))
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetPodDoesNotExist(t *testing.T) {
|
||||
runForAllStates(t, func(t *testing.T, state State, lockPath string) {
|
||||
_, err := state.Pod("doesnotexist")
|
||||
|
|
Loading…
Reference in New Issue