nri: add experimental NRI plugin.
Add a common NRI 'service' plugin. It takes care of relaying requests and respones to and from NRI (external NRI plugins) and the high-level containerd namespace-independent logic of applying NRI container adjustments and updates to actual CRI and other containers. The namespace-dependent details of the necessary container manipulation operations are to be implemented by namespace- specific adaptations. This NRI plugin defines the API which such adaptations need to implement. Signed-off-by: Krisztian Litkey <krisztian.litkey@intel.com>
This commit is contained in:
183
pkg/nri/domain.go
Normal file
183
pkg/nri/domain.go
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package nri
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
nri "github.com/containerd/nri/pkg/adaptation"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Domain implements the functions the generic NRI interface needs to
|
||||
// deal with pods and containers from a particular containerd namespace.
|
||||
type Domain interface {
|
||||
// GetName() returns the containerd namespace for this domain.
|
||||
GetName() string
|
||||
|
||||
// ListPodSandboxes list all pods in this namespace.
|
||||
ListPodSandboxes() []PodSandbox
|
||||
|
||||
// ListContainer list all containers in this namespace.
|
||||
ListContainers() []Container
|
||||
|
||||
// GetPodSandbox returns the pod for the given ID.
|
||||
GetPodSandbox(string) (PodSandbox, bool)
|
||||
|
||||
// GetContainer returns the container for the given ID.
|
||||
GetContainer(string) (Container, bool)
|
||||
|
||||
// UpdateContainer applies an NRI container update request in the namespace.
|
||||
UpdateContainer(context.Context, *nri.ContainerUpdate) error
|
||||
|
||||
// EvictContainer evicts the requested container in the namespace.
|
||||
EvictContainer(context.Context, *nri.ContainerEviction) error
|
||||
}
|
||||
|
||||
// RegisterDomain registers an NRI domain for a containerd namespace.
|
||||
func RegisterDomain(d Domain) {
|
||||
err := domains.add(d)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Fatalf("Failed to register namespace %q with NRI", d.GetName())
|
||||
}
|
||||
|
||||
logrus.Infof("Registered namespace %q with NRI", d.GetName())
|
||||
}
|
||||
|
||||
type domainTable struct {
|
||||
sync.Mutex
|
||||
domains map[string]Domain
|
||||
}
|
||||
|
||||
func (t *domainTable) add(d Domain) error {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
namespace := d.GetName()
|
||||
|
||||
if _, ok := t.domains[namespace]; ok {
|
||||
return errdefs.ErrAlreadyExists
|
||||
}
|
||||
|
||||
t.domains[namespace] = d
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *domainTable) listPodSandboxes() []PodSandbox {
|
||||
var pods []PodSandbox
|
||||
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
for _, d := range t.domains {
|
||||
pods = append(pods, d.ListPodSandboxes()...)
|
||||
}
|
||||
return pods
|
||||
}
|
||||
|
||||
func (t *domainTable) listContainers() []Container {
|
||||
var ctrs []Container
|
||||
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
for _, d := range t.domains {
|
||||
ctrs = append(ctrs, d.ListContainers()...)
|
||||
}
|
||||
return ctrs
|
||||
}
|
||||
|
||||
func (t *domainTable) getContainer(id string) (Container, Domain) {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
// TODO(klihub): Are ID conflicts across namespaces possible ? Probably...
|
||||
|
||||
for _, d := range t.domains {
|
||||
if ctr, ok := d.GetContainer(id); ok {
|
||||
return ctr, d
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (t *domainTable) updateContainers(ctx context.Context, updates []*nri.ContainerUpdate) ([]*nri.ContainerUpdate, error) {
|
||||
var failed []*nri.ContainerUpdate
|
||||
|
||||
for _, u := range updates {
|
||||
_, d := t.getContainer(u.ContainerId)
|
||||
if d == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
domain := d.GetName()
|
||||
err := d.UpdateContainer(namespaces.WithNamespace(ctx, domain), u)
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Errorf("NRI update of %s container %s failed",
|
||||
domain, u.ContainerId)
|
||||
if !u.IgnoreFailure {
|
||||
failed = append(failed, u)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
log.G(ctx).Tracef("NRI update of %s container %s successful", domain, u.ContainerId)
|
||||
}
|
||||
|
||||
if len(failed) != 0 {
|
||||
return failed, fmt.Errorf("NRI update of some containers failed")
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (t *domainTable) evictContainers(ctx context.Context, evict []*nri.ContainerEviction) ([]*nri.ContainerEviction, error) {
|
||||
var failed []*nri.ContainerEviction
|
||||
|
||||
for _, e := range evict {
|
||||
_, d := t.getContainer(e.ContainerId)
|
||||
if d == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
domain := d.GetName()
|
||||
err := d.EvictContainer(namespaces.WithNamespace(ctx, domain), e)
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Errorf("NRI eviction of %s container %s failed",
|
||||
domain, e.ContainerId)
|
||||
failed = append(failed, e)
|
||||
continue
|
||||
}
|
||||
|
||||
log.G(ctx).Tracef("NRI eviction of %s container %s successful", domain, e.ContainerId)
|
||||
}
|
||||
|
||||
if len(failed) != 0 {
|
||||
return failed, fmt.Errorf("NRI eviction of some containers failed")
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var domains = &domainTable{
|
||||
domains: make(map[string]Domain),
|
||||
}
|
||||
Reference in New Issue
Block a user