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
|
// Namespace Config
|
||||||
// IDs of container to share namespaces with
|
// IDs of container to share namespaces with
|
||||||
// NetNsCtr conflicts with the CreateNetNS bool
|
// 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"`
|
IPCNsCtr string `json:"ipcNsCtr,omitempty"`
|
||||||
MountNsCtr string `json:"mountNsCtr,omitempty"`
|
MountNsCtr string `json:"mountNsCtr,omitempty"`
|
||||||
NetNsCtr string `json:"netNsCtr,omitempty"`
|
NetNsCtr string `json:"netNsCtr,omitempty"`
|
||||||
|
@ -213,6 +215,10 @@ type ContainerConfig struct {
|
||||||
UTSNsCtr string `json:"utsNsCtr,omitempty"`
|
UTSNsCtr string `json:"utsNsCtr,omitempty"`
|
||||||
CgroupNsCtr string `json:"cgroupNsCtr,omitempty"`
|
CgroupNsCtr string `json:"cgroupNsCtr,omitempty"`
|
||||||
|
|
||||||
|
// IDs of dependency containers
|
||||||
|
// These containers must be started before this container is started
|
||||||
|
Dependencies []string
|
||||||
|
|
||||||
// Network Config
|
// Network Config
|
||||||
// CreateNetNS indicates that libpod should create and configure a new
|
// CreateNetNS indicates that libpod should create and configure a new
|
||||||
// network namespace for the container
|
// network namespace for the container
|
||||||
|
@ -363,6 +369,8 @@ func (c *Container) User() string {
|
||||||
func (c *Container) Dependencies() []string {
|
func (c *Container) Dependencies() []string {
|
||||||
// Collect in a map first to remove dupes
|
// Collect in a map first to remove dupes
|
||||||
dependsCtrs := map[string]bool{}
|
dependsCtrs := map[string]bool{}
|
||||||
|
|
||||||
|
// First add all namespace containers
|
||||||
if c.config.IPCNsCtr != "" {
|
if c.config.IPCNsCtr != "" {
|
||||||
dependsCtrs[c.config.IPCNsCtr] = true
|
dependsCtrs[c.config.IPCNsCtr] = true
|
||||||
}
|
}
|
||||||
|
@ -385,6 +393,11 @@ func (c *Container) Dependencies() []string {
|
||||||
dependsCtrs[c.config.CgroupNsCtr] = true
|
dependsCtrs[c.config.CgroupNsCtr] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add all generic dependencies
|
||||||
|
for _, id := range c.config.Dependencies {
|
||||||
|
dependsCtrs[id] = true
|
||||||
|
}
|
||||||
|
|
||||||
if len(dependsCtrs) == 0 {
|
if len(dependsCtrs) == 0 {
|
||||||
return []string{}
|
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
|
// WithNetNS indicates that the container should be given a new network
|
||||||
// namespace with a minimal configuration
|
// namespace with a minimal configuration
|
||||||
// An optional array of port mappings can be provided
|
// 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) {
|
func TestCannotRemoveContainerWithDependency(t *testing.T) {
|
||||||
runForAllStates(t, func(t *testing.T, state State, lockPath string) {
|
runForAllStates(t, func(t *testing.T, state State, lockPath string) {
|
||||||
testCtr1, err := getTestCtr1(lockPath)
|
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) {
|
func TestCanRemoveContainerAfterDependencyRemoved(t *testing.T) {
|
||||||
runForAllStates(t, func(t *testing.T, state State, lockPath string) {
|
runForAllStates(t, func(t *testing.T, state State, lockPath string) {
|
||||||
testCtr1, err := getTestCtr1(lockPath)
|
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) {
|
func TestGetPodDoesNotExist(t *testing.T) {
|
||||||
runForAllStates(t, func(t *testing.T, state State, lockPath string) {
|
runForAllStates(t, func(t *testing.T, state State, lockPath string) {
|
||||||
_, err := state.Pod("doesnotexist")
|
_, err := state.Pod("doesnotexist")
|
||||||
|
|
Loading…
Reference in New Issue