Merge pull request #1198 from runcom/list-sandboxes-refactor
lib: sandbox: refactor to memory store
This commit is contained in:
commit
85f303f3ff
5 changed files with 173 additions and 24 deletions
|
@ -168,7 +168,7 @@ func New(config *Config) (*ContainerServer, error) {
|
||||||
state: &containerServerState{
|
state: &containerServerState{
|
||||||
containers: oci.NewMemoryStore(),
|
containers: oci.NewMemoryStore(),
|
||||||
infraContainers: oci.NewMemoryStore(),
|
infraContainers: oci.NewMemoryStore(),
|
||||||
sandboxes: make(map[string]*sandbox.Sandbox),
|
sandboxes: sandbox.NewMemoryStore(),
|
||||||
processLevels: make(map[string]int),
|
processLevels: make(map[string]int),
|
||||||
},
|
},
|
||||||
config: config,
|
config: config,
|
||||||
|
@ -617,7 +617,7 @@ func (c *ContainerServer) Shutdown() error {
|
||||||
type containerServerState struct {
|
type containerServerState struct {
|
||||||
containers oci.ContainerStorer
|
containers oci.ContainerStorer
|
||||||
infraContainers oci.ContainerStorer
|
infraContainers oci.ContainerStorer
|
||||||
sandboxes map[string]*sandbox.Sandbox
|
sandboxes sandbox.Storer
|
||||||
// processLevels The number of sandboxes using the same SELinux MCS level. Need to release MCS Level, when count reaches 0
|
// processLevels The number of sandboxes using the same SELinux MCS level. Need to release MCS Level, when count reaches 0
|
||||||
processLevels map[string]int
|
processLevels map[string]int
|
||||||
}
|
}
|
||||||
|
@ -626,7 +626,7 @@ type containerServerState struct {
|
||||||
func (c *ContainerServer) AddContainer(ctr *oci.Container) {
|
func (c *ContainerServer) AddContainer(ctr *oci.Container) {
|
||||||
c.stateLock.Lock()
|
c.stateLock.Lock()
|
||||||
defer c.stateLock.Unlock()
|
defer c.stateLock.Unlock()
|
||||||
sandbox := c.state.sandboxes[ctr.Sandbox()]
|
sandbox := c.state.sandboxes.Get(ctr.Sandbox())
|
||||||
sandbox.AddContainer(ctr)
|
sandbox.AddContainer(ctr)
|
||||||
c.state.containers.Add(ctr.ID(), ctr)
|
c.state.containers.Add(ctr.ID(), ctr)
|
||||||
}
|
}
|
||||||
|
@ -665,7 +665,7 @@ func (c *ContainerServer) RemoveContainer(ctr *oci.Container) {
|
||||||
c.stateLock.Lock()
|
c.stateLock.Lock()
|
||||||
defer c.stateLock.Unlock()
|
defer c.stateLock.Unlock()
|
||||||
sbID := ctr.Sandbox()
|
sbID := ctr.Sandbox()
|
||||||
sb := c.state.sandboxes[sbID]
|
sb := c.state.sandboxes.Get(sbID)
|
||||||
sb.RemoveContainer(ctr)
|
sb.RemoveContainer(ctr)
|
||||||
c.state.containers.Delete(ctr.ID())
|
c.state.containers.Delete(ctr.ID())
|
||||||
}
|
}
|
||||||
|
@ -706,7 +706,7 @@ func (c *ContainerServer) ListContainers(filters ...func(*oci.Container) bool) (
|
||||||
func (c *ContainerServer) AddSandbox(sb *sandbox.Sandbox) {
|
func (c *ContainerServer) AddSandbox(sb *sandbox.Sandbox) {
|
||||||
c.stateLock.Lock()
|
c.stateLock.Lock()
|
||||||
defer c.stateLock.Unlock()
|
defer c.stateLock.Unlock()
|
||||||
c.state.sandboxes[sb.ID()] = sb
|
c.state.sandboxes.Add(sb.ID(), sb)
|
||||||
c.state.processLevels[selinux.NewContext(sb.ProcessLabel())["level"]]++
|
c.state.processLevels[selinux.NewContext(sb.ProcessLabel())["level"]]++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -714,17 +714,14 @@ func (c *ContainerServer) AddSandbox(sb *sandbox.Sandbox) {
|
||||||
func (c *ContainerServer) GetSandbox(id string) *sandbox.Sandbox {
|
func (c *ContainerServer) GetSandbox(id string) *sandbox.Sandbox {
|
||||||
c.stateLock.Lock()
|
c.stateLock.Lock()
|
||||||
defer c.stateLock.Unlock()
|
defer c.stateLock.Unlock()
|
||||||
return c.state.sandboxes[id]
|
return c.state.sandboxes.Get(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSandboxContainer returns a sandbox's infra container
|
// GetSandboxContainer returns a sandbox's infra container
|
||||||
func (c *ContainerServer) GetSandboxContainer(id string) *oci.Container {
|
func (c *ContainerServer) GetSandboxContainer(id string) *oci.Container {
|
||||||
c.stateLock.Lock()
|
c.stateLock.Lock()
|
||||||
defer c.stateLock.Unlock()
|
defer c.stateLock.Unlock()
|
||||||
sb, ok := c.state.sandboxes[id]
|
sb := c.state.sandboxes.Get(id)
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return sb.InfraContainer()
|
return sb.InfraContainer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,34 +729,33 @@ func (c *ContainerServer) GetSandboxContainer(id string) *oci.Container {
|
||||||
func (c *ContainerServer) HasSandbox(id string) bool {
|
func (c *ContainerServer) HasSandbox(id string) bool {
|
||||||
c.stateLock.Lock()
|
c.stateLock.Lock()
|
||||||
defer c.stateLock.Unlock()
|
defer c.stateLock.Unlock()
|
||||||
_, ok := c.state.sandboxes[id]
|
sb := c.state.sandboxes.Get(id)
|
||||||
return ok
|
return sb != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveSandbox removes a sandbox from the state store
|
// RemoveSandbox removes a sandbox from the state store
|
||||||
func (c *ContainerServer) RemoveSandbox(id string) {
|
func (c *ContainerServer) RemoveSandbox(id string) {
|
||||||
c.stateLock.Lock()
|
c.stateLock.Lock()
|
||||||
defer c.stateLock.Unlock()
|
defer c.stateLock.Unlock()
|
||||||
processLabel := c.state.sandboxes[id].ProcessLabel()
|
sb := c.state.sandboxes.Get(id)
|
||||||
delete(c.state.sandboxes, id)
|
processLabel := sb.ProcessLabel()
|
||||||
|
c.state.sandboxes.Delete(id)
|
||||||
level := selinux.NewContext(processLabel)["level"]
|
level := selinux.NewContext(processLabel)["level"]
|
||||||
c.state.processLevels[level]--
|
pl, ok := c.state.processLevels[level]
|
||||||
|
if ok {
|
||||||
|
c.state.processLevels[level] = pl - 1
|
||||||
if c.state.processLevels[level] == 0 {
|
if c.state.processLevels[level] == 0 {
|
||||||
label.ReleaseLabel(processLabel)
|
label.ReleaseLabel(processLabel)
|
||||||
delete(c.state.processLevels, level)
|
delete(c.state.processLevels, level)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListSandboxes lists all sandboxes in the state store
|
// ListSandboxes lists all sandboxes in the state store
|
||||||
func (c *ContainerServer) ListSandboxes() []*sandbox.Sandbox {
|
func (c *ContainerServer) ListSandboxes() []*sandbox.Sandbox {
|
||||||
c.stateLock.Lock()
|
c.stateLock.Lock()
|
||||||
defer c.stateLock.Unlock()
|
defer c.stateLock.Unlock()
|
||||||
sbArray := make([]*sandbox.Sandbox, 0, len(c.state.sandboxes))
|
return c.state.sandboxes.List()
|
||||||
for _, sb := range c.state.sandboxes {
|
|
||||||
sbArray = append(sbArray, sb)
|
|
||||||
}
|
|
||||||
|
|
||||||
return sbArray
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LibcontainerStats gets the stats for the container with the given id from runc/libcontainer
|
// LibcontainerStats gets the stats for the container with the given id from runc/libcontainer
|
||||||
|
|
31
lib/sandbox/history.go
Normal file
31
lib/sandbox/history.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package sandbox
|
||||||
|
|
||||||
|
import "sort"
|
||||||
|
|
||||||
|
// History is a convenience type for storing a list of sandboxes,
|
||||||
|
// sorted by creation date in descendant order.
|
||||||
|
type History []*Sandbox
|
||||||
|
|
||||||
|
// Len returns the number of sandboxes in the history.
|
||||||
|
func (history *History) Len() int {
|
||||||
|
return len(*history)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Less compares two sandboxes and returns true if the second one
|
||||||
|
// was created before the first one.
|
||||||
|
func (history *History) Less(i, j int) bool {
|
||||||
|
sandboxes := *history
|
||||||
|
// FIXME: state access should be serialized
|
||||||
|
return sandboxes[j].created.Before(sandboxes[i].created)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap switches sandboxes i and j positions in the history.
|
||||||
|
func (history *History) Swap(i, j int) {
|
||||||
|
sandboxes := *history
|
||||||
|
sandboxes[i], sandboxes[j] = sandboxes[j], sandboxes[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort orders the history by creation date in descendant order.
|
||||||
|
func (history *History) sort() {
|
||||||
|
sort.Sort(history)
|
||||||
|
}
|
92
lib/sandbox/memory_store.go
Normal file
92
lib/sandbox/memory_store.go
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
package sandbox
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
// memoryStore implements a Store in memory.
|
||||||
|
type memoryStore struct {
|
||||||
|
s map[string]*Sandbox
|
||||||
|
sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMemoryStore initializes a new memory store.
|
||||||
|
func NewMemoryStore() Storer {
|
||||||
|
return &memoryStore{
|
||||||
|
s: make(map[string]*Sandbox),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add appends a new sandbox to the memory store.
|
||||||
|
// It overrides the id if it existed before.
|
||||||
|
func (c *memoryStore) Add(id string, cont *Sandbox) {
|
||||||
|
c.Lock()
|
||||||
|
c.s[id] = cont
|
||||||
|
c.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns a sandbox from the store by id.
|
||||||
|
func (c *memoryStore) Get(id string) *Sandbox {
|
||||||
|
c.RLock()
|
||||||
|
res := c.s[id]
|
||||||
|
c.RUnlock()
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete removes a sandbox from the store by id.
|
||||||
|
func (c *memoryStore) Delete(id string) {
|
||||||
|
c.Lock()
|
||||||
|
delete(c.s, id)
|
||||||
|
c.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns a sorted list of sandboxes from the store.
|
||||||
|
// The sandboxes are ordered by creation date.
|
||||||
|
func (c *memoryStore) List() []*Sandbox {
|
||||||
|
sandboxes := History(c.all())
|
||||||
|
sandboxes.sort()
|
||||||
|
return sandboxes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the number of sandboxes in the store.
|
||||||
|
func (c *memoryStore) Size() int {
|
||||||
|
c.RLock()
|
||||||
|
defer c.RUnlock()
|
||||||
|
return len(c.s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// First returns the first sandbox found in the store by a given filter.
|
||||||
|
func (c *memoryStore) First(filter StoreFilter) *Sandbox {
|
||||||
|
for _, cont := range c.all() {
|
||||||
|
if filter(cont) {
|
||||||
|
return cont
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyAll calls the reducer function with every sandbox in the store.
|
||||||
|
// This operation is asynchronous in the memory store.
|
||||||
|
// NOTE: Modifications to the store MUST NOT be done by the StoreReducer.
|
||||||
|
func (c *memoryStore) ApplyAll(apply StoreReducer) {
|
||||||
|
wg := new(sync.WaitGroup)
|
||||||
|
for _, cont := range c.all() {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(sandbox *Sandbox) {
|
||||||
|
apply(sandbox)
|
||||||
|
wg.Done()
|
||||||
|
}(cont)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *memoryStore) all() []*Sandbox {
|
||||||
|
c.RLock()
|
||||||
|
sandboxes := make([]*Sandbox, 0, len(c.s))
|
||||||
|
for _, cont := range c.s {
|
||||||
|
sandboxes = append(sandboxes, cont)
|
||||||
|
}
|
||||||
|
c.RUnlock()
|
||||||
|
return sandboxes
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Storer = &memoryStore{}
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/docker/docker/pkg/mount"
|
"github.com/docker/docker/pkg/mount"
|
||||||
|
@ -158,6 +159,7 @@ type Sandbox struct {
|
||||||
// ipv4 or ipv6 cache
|
// ipv4 or ipv6 cache
|
||||||
ip string
|
ip string
|
||||||
seccompProfilePath string
|
seccompProfilePath string
|
||||||
|
created time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -202,6 +204,7 @@ func New(id, namespace, name, kubeName, logDir string, labels, annotations map[s
|
||||||
sb.resolvPath = resolvPath
|
sb.resolvPath = resolvPath
|
||||||
sb.hostname = hostname
|
sb.hostname = hostname
|
||||||
sb.portMappings = portMappings
|
sb.portMappings = portMappings
|
||||||
|
sb.created = time.Now()
|
||||||
|
|
||||||
return sb, nil
|
return sb, nil
|
||||||
}
|
}
|
||||||
|
|
27
lib/sandbox/store.go
Normal file
27
lib/sandbox/store.go
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package sandbox
|
||||||
|
|
||||||
|
// StoreFilter defines a function to filter
|
||||||
|
// sandboxes in the store.
|
||||||
|
type StoreFilter func(*Sandbox) bool
|
||||||
|
|
||||||
|
// StoreReducer defines a function to
|
||||||
|
// manipulate sandboxes in the store
|
||||||
|
type StoreReducer func(*Sandbox)
|
||||||
|
|
||||||
|
// Storer defines an interface that any container store must implement.
|
||||||
|
type Storer interface {
|
||||||
|
// Add appends a new sandbox to the store.
|
||||||
|
Add(string, *Sandbox)
|
||||||
|
// Get returns a sandbox from the store by the identifier it was stored with.
|
||||||
|
Get(string) *Sandbox
|
||||||
|
// Delete removes a sandbox from the store by the identifier it was stored with.
|
||||||
|
Delete(string)
|
||||||
|
// List returns a list of sandboxes from the store.
|
||||||
|
List() []*Sandbox
|
||||||
|
// Size returns the number of sandboxes in the store.
|
||||||
|
Size() int
|
||||||
|
// First returns the first sandbox found in the store by a given filter.
|
||||||
|
First(StoreFilter) *Sandbox
|
||||||
|
// ApplyAll calls the reducer function with every sandbox in the store.
|
||||||
|
ApplyAll(StoreReducer)
|
||||||
|
}
|
Loading…
Reference in a new issue