mirror of
https://github.com/containers/podman.git
synced 2025-07-18 01:57:24 +08:00
Add pod functions to BoltDB state
Signed-off-by: Matthew Heon <matthew.heon@gmail.com> Closes: #184 Approved by: baude
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -3,34 +3,42 @@ package libpod
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/boltdb/bolt"
|
"github.com/boltdb/bolt"
|
||||||
"github.com/containers/storage"
|
"github.com/containers/storage"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
idRegistryName = "id-registry"
|
idRegistryName = "id-registry"
|
||||||
nameRegistryName = "name-registry"
|
nameRegistryName = "name-registry"
|
||||||
ctrConfigName = "container-config"
|
ctrName = "ctr"
|
||||||
ctrStateName = "container-state"
|
|
||||||
netNSName = "net-ns"
|
|
||||||
runtimeConfigName = "runtime-config"
|
|
||||||
ctrDependsName = "container-depends"
|
|
||||||
podName = "pod"
|
podName = "pod"
|
||||||
podContainersName = "pod-containers"
|
runtimeConfigName = "runtime-config"
|
||||||
|
|
||||||
|
configName = "config"
|
||||||
|
stateName = "state"
|
||||||
|
dependenciesName = "dependencies"
|
||||||
|
netNSName = "netns"
|
||||||
|
containersName = "containers"
|
||||||
|
|
||||||
|
dbExistName = "ok"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
idRegistryBkt = []byte(idRegistryName)
|
idRegistryBkt = []byte(idRegistryName)
|
||||||
nameRegistryBkt = []byte(nameRegistryName)
|
nameRegistryBkt = []byte(nameRegistryName)
|
||||||
ctrConfigBkt = []byte(ctrConfigName)
|
ctrBkt = []byte(ctrName)
|
||||||
ctrStateBkt = []byte(ctrStateName)
|
|
||||||
netNSBkt = []byte(netNSName)
|
|
||||||
runtimeConfigBkt = []byte(runtimeConfigName)
|
|
||||||
ctrDependsBkt = []byte(ctrDependsName)
|
|
||||||
podBkt = []byte(podName)
|
podBkt = []byte(podName)
|
||||||
podContainersBkt = []byte(podContainersName)
|
runtimeConfigBkt = []byte(runtimeConfigName)
|
||||||
|
|
||||||
|
configKey = []byte(configName)
|
||||||
|
stateKey = []byte(stateName)
|
||||||
|
dependenciesBkt = []byte(dependenciesName)
|
||||||
|
netNSKey = []byte(netNSName)
|
||||||
|
containersBkt = []byte(containersName)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Check if the configuration of the database is compatible with the
|
// Check if the configuration of the database is compatible with the
|
||||||
@ -122,42 +130,10 @@ func getNamesBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
|
|||||||
return bkt, nil
|
return bkt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCtrConfigBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
|
func getCtrBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
|
||||||
bkt := tx.Bucket(ctrConfigBkt)
|
bkt := tx.Bucket(ctrBkt)
|
||||||
if bkt == nil {
|
if bkt == nil {
|
||||||
return nil, errors.Wrapf(ErrDBBadConfig, "container config bucket not found in DB")
|
return nil, errors.Wrapf(ErrDBBadConfig, "containers bucket not found in DB")
|
||||||
}
|
|
||||||
return bkt, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCtrStateBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
|
|
||||||
bkt := tx.Bucket(ctrStateBkt)
|
|
||||||
if bkt == nil {
|
|
||||||
return nil, errors.Wrapf(ErrDBBadConfig, "container state bucket not found in DB")
|
|
||||||
}
|
|
||||||
return bkt, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getNetNSBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
|
|
||||||
bkt := tx.Bucket(netNSBkt)
|
|
||||||
if bkt == nil {
|
|
||||||
return nil, errors.Wrapf(ErrDBBadConfig, "network namespace bucket not found in DB")
|
|
||||||
}
|
|
||||||
return bkt, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRuntimeConfigBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
|
|
||||||
bkt := tx.Bucket(runtimeConfigBkt)
|
|
||||||
if bkt == nil {
|
|
||||||
return nil, errors.Wrapf(ErrDBBadConfig, "runtime configuration bucket not found in DB")
|
|
||||||
}
|
|
||||||
return bkt, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCtrDependsBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
|
|
||||||
bkt := tx.Bucket(ctrDependsBkt)
|
|
||||||
if bkt == nil {
|
|
||||||
return nil, errors.Wrapf(ErrDBBadConfig, "container dependencies bucket not found in DB")
|
|
||||||
}
|
}
|
||||||
return bkt, nil
|
return bkt, nil
|
||||||
}
|
}
|
||||||
@ -170,36 +146,42 @@ func getPodBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
|
|||||||
return bkt, nil
|
return bkt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPodContainersBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
|
func getRuntimeConfigBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
|
||||||
bkt := tx.Bucket(podContainersBkt)
|
bkt := tx.Bucket(runtimeConfigBkt)
|
||||||
if bkt == nil {
|
if bkt == nil {
|
||||||
return nil, errors.Wrapf(ErrDBBadConfig, "pod containers bucket not found in DB")
|
return nil, errors.Wrapf(ErrDBBadConfig, "runtime configuration bucket not found in DB")
|
||||||
}
|
}
|
||||||
return bkt, nil
|
return bkt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, config, state, netNS *bolt.Bucket) error {
|
func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, ctrsBkt *bolt.Bucket) error {
|
||||||
configBytes := config.Get(id)
|
ctrBkt := ctrsBkt.Bucket(id)
|
||||||
if configBytes == nil {
|
if ctrBkt == nil {
|
||||||
return errors.Wrapf(ErrNoSuchCtr, "error unmarshalling container %s config", string(id))
|
return errors.Wrapf(ErrNoSuchCtr, "container %s not found in DB", string(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configBytes := ctrBkt.Get(configKey)
|
||||||
|
if configBytes == nil {
|
||||||
|
return errors.Wrapf(ErrInternal, "container %s missing config key in DB", string(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
stateBytes := ctrBkt.Get(stateKey)
|
||||||
|
if stateBytes == nil {
|
||||||
|
return errors.Wrapf(ErrInternal, "container %s missing state key in DB", string(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
netNSBytes := ctrBkt.Get(netNSKey)
|
||||||
|
|
||||||
if err := json.Unmarshal(configBytes, ctr.config); err != nil {
|
if err := json.Unmarshal(configBytes, ctr.config); err != nil {
|
||||||
return errors.Wrapf(err, "error unmarshalling container %s config", string(id))
|
return errors.Wrapf(err, "error unmarshalling container %s config", string(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
stateBytes := state.Get(id)
|
|
||||||
if stateBytes == nil {
|
|
||||||
return errors.Wrapf(ErrInternal, "container %s has config but no state", string(id))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.Unmarshal(stateBytes, ctr.state); err != nil {
|
if err := json.Unmarshal(stateBytes, ctr.state); err != nil {
|
||||||
return errors.Wrapf(err, "error unmarshalling container %s state", string(id))
|
return errors.Wrapf(err, "error unmarshalling container %s state", string(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
// The container may not have a network namespace, so it's OK if this is
|
// The container may not have a network namespace, so it's OK if this is
|
||||||
// nil
|
// nil
|
||||||
netNSBytes := netNS.Get(id)
|
|
||||||
if netNSBytes != nil {
|
if netNSBytes != nil {
|
||||||
nsPath := string(netNSBytes)
|
nsPath := string(netNSBytes)
|
||||||
netNS, err := joinNetNS(nsPath)
|
netNS, err := joinNetNS(nsPath)
|
||||||
@ -222,3 +204,293 @@ func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, config, state,
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *BoltState) getPodFromDB(id []byte, pod *Pod, podBkt *bolt.Bucket) error {
|
||||||
|
podDB := podBkt.Bucket(id)
|
||||||
|
if podDB == nil {
|
||||||
|
return errors.Wrapf(ErrNoSuchPod, "pod with ID %s not found", string(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
podBytes := podDB.Get(configKey)
|
||||||
|
if podBytes == nil {
|
||||||
|
return errors.Wrapf(ErrInternal, "pod %s is missing configuration key in DB", string(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(podBytes, pod); err != nil {
|
||||||
|
return errors.Wrapf(err, "error unmarshalling pod %s from DB", string(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the lock
|
||||||
|
lockPath := filepath.Join(s.lockDir, string(id))
|
||||||
|
lock, err := storage.GetLockfile(lockPath)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error retrieving lockfile for pod %s", string(id))
|
||||||
|
}
|
||||||
|
pod.lock = lock
|
||||||
|
|
||||||
|
pod.runtime = s.runtime
|
||||||
|
pod.valid = true
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a container to the DB
|
||||||
|
// If pod is not nil, the container is added to the pod as well
|
||||||
|
func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
|
||||||
|
// JSON container structs to insert into DB
|
||||||
|
// TODO use a higher-performance struct encoding than JSON
|
||||||
|
configJSON, err := json.Marshal(ctr.config)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error marshalling container %s config to JSON", ctr.ID())
|
||||||
|
}
|
||||||
|
stateJSON, err := json.Marshal(ctr.state)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error marshalling container %s state to JSON", ctr.ID())
|
||||||
|
}
|
||||||
|
netNSPath := ""
|
||||||
|
if ctr.state.NetNS != nil {
|
||||||
|
netNSPath = ctr.state.NetNS.Path()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependsCtrs := ctr.Dependencies()
|
||||||
|
|
||||||
|
ctrID := []byte(ctr.ID())
|
||||||
|
ctrName := []byte(ctr.Name())
|
||||||
|
|
||||||
|
db, err := s.getDBCon()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
err = db.Update(func(tx *bolt.Tx) error {
|
||||||
|
idsBucket, err := getIDBucket(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
namesBucket, err := getNamesBucket(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrBucket, err := getCtrBucket(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a pod was given, check if it exists
|
||||||
|
var podDB *bolt.Bucket
|
||||||
|
var podCtrs *bolt.Bucket
|
||||||
|
if pod != nil {
|
||||||
|
podBucket, err := getPodBucket(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
podID := []byte(pod.ID())
|
||||||
|
|
||||||
|
podDB = podBucket.Bucket(podID)
|
||||||
|
if podDB == nil {
|
||||||
|
pod.valid = false
|
||||||
|
return errors.Wrapf(ErrNoSuchPod, "pod %s does not exist in database", pod.ID())
|
||||||
|
}
|
||||||
|
podCtrs = podDB.Bucket(containersBkt)
|
||||||
|
if podCtrs == nil {
|
||||||
|
return errors.Wrapf(ErrInternal, "pod %s does not have a containers bucket", pod.ID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we already have a container with the given ID and name
|
||||||
|
idExist := idsBucket.Get(ctrID)
|
||||||
|
if idExist != nil {
|
||||||
|
return errors.Wrapf(ErrCtrExists, "ID %s is in use", ctr.ID())
|
||||||
|
}
|
||||||
|
nameExist := namesBucket.Get(ctrName)
|
||||||
|
if nameExist != nil {
|
||||||
|
return errors.Wrapf(ErrCtrExists, "name %s is in use", ctr.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
// No overlapping containers
|
||||||
|
// Add the new container to the DB
|
||||||
|
if err := idsBucket.Put(ctrID, ctrName); err != nil {
|
||||||
|
return errors.Wrapf(err, "error adding container %s ID to DB", ctr.ID())
|
||||||
|
}
|
||||||
|
if err := namesBucket.Put(ctrName, ctrID); err != nil {
|
||||||
|
return errors.Wrapf(err, "error adding container %s name (%s) to DB", ctr.ID(), ctr.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
newCtrBkt, err := ctrBucket.CreateBucket(ctrID)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error adding container %s bucket to DB", ctr.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := newCtrBkt.Put(configKey, configJSON); err != nil {
|
||||||
|
return errors.Wrapf(err, "error adding container %s config to DB", ctr.ID())
|
||||||
|
}
|
||||||
|
if err := newCtrBkt.Put(stateKey, stateJSON); err != nil {
|
||||||
|
return errors.Wrapf(err, "error adding container %s state to DB", ctr.ID())
|
||||||
|
}
|
||||||
|
if netNSPath != "" {
|
||||||
|
if err := newCtrBkt.Put(netNSKey, []byte(netNSPath)); err != nil {
|
||||||
|
return errors.Wrapf(err, "error adding container %s netns path to DB", ctr.ID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err := newCtrBkt.CreateBucket(dependenciesBkt); err != nil {
|
||||||
|
return errors.Wrapf(err, "error creating dependencies bucket for container %s", ctr.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add dependencies for the container
|
||||||
|
for _, dependsCtr := range dependsCtrs {
|
||||||
|
depCtrID := []byte(dependsCtr)
|
||||||
|
|
||||||
|
depCtrBkt := ctrBucket.Bucket(depCtrID)
|
||||||
|
if depCtrBkt == nil {
|
||||||
|
return errors.Wrapf(ErrNoSuchCtr, "container %s depends on container %s, but it does not exist in the DB", ctr.ID(), dependsCtr)
|
||||||
|
}
|
||||||
|
depCtrDependsBkt := depCtrBkt.Bucket(dependenciesBkt)
|
||||||
|
if depCtrDependsBkt == nil {
|
||||||
|
return errors.Wrapf(ErrInternal, "container %s does not have a dependencies bucket", dependsCtr)
|
||||||
|
}
|
||||||
|
if err := depCtrDependsBkt.Put(ctrID, ctrName); err != nil {
|
||||||
|
return errors.Wrapf(err, "error adding ctr %s as dependency of container %s", ctr.ID(), dependsCtr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add ctr to pod
|
||||||
|
if pod != nil {
|
||||||
|
if err := podCtrs.Put(ctrID, ctrName); err != nil {
|
||||||
|
return errors.Wrapf(err, "error adding container %s to pod %s", ctr.ID(), pod.ID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove a container from the DB
|
||||||
|
// If pod is not nil, the container is treated as belonging to a pod, and
|
||||||
|
// will be removed from the pod as well
|
||||||
|
func removeContainer(ctr *Container, pod *Pod, tx *bolt.Tx) error {
|
||||||
|
ctrID := []byte(ctr.ID())
|
||||||
|
ctrName := []byte(ctr.Name())
|
||||||
|
|
||||||
|
idsBucket, err := getIDBucket(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
namesBucket, err := getNamesBucket(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrBucket, err := getCtrBucket(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does the pod exist?
|
||||||
|
var podDB *bolt.Bucket
|
||||||
|
if pod != nil {
|
||||||
|
podBucket, err := getPodBucket(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
podID := []byte(pod.ID())
|
||||||
|
|
||||||
|
podDB = podBucket.Bucket(podID)
|
||||||
|
if podDB == nil {
|
||||||
|
pod.valid = false
|
||||||
|
return errors.Wrapf(ErrNoSuchPod, "no pod with ID %s found in DB", pod.ID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does the container exist?
|
||||||
|
ctrExists := ctrBucket.Bucket(ctrID)
|
||||||
|
if ctrExists == nil {
|
||||||
|
ctr.valid = false
|
||||||
|
return errors.Wrapf(ErrNoSuchCtr, "no container with ID %s found in DB", ctr.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
if podDB != nil {
|
||||||
|
// Check if the container is in the pod, remove it if it is
|
||||||
|
podCtrs := podDB.Bucket(containersBkt)
|
||||||
|
if podCtrs == nil {
|
||||||
|
// Malformed pod
|
||||||
|
logrus.Errorf("pod %s malformed in database, missing containers bucket!", pod.ID())
|
||||||
|
} else {
|
||||||
|
ctrInPod := podCtrs.Get(ctrID)
|
||||||
|
if ctrInPod == nil {
|
||||||
|
return errors.Wrapf(ErrNoSuchCtr, "container %s is not in pod %s", ctr.ID(), pod.ID())
|
||||||
|
}
|
||||||
|
if err := podCtrs.Delete(ctrID); err != nil {
|
||||||
|
return errors.Wrapf(err, "error removing container %s from pod %s", ctr.ID(), pod.ID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does the container have dependencies?
|
||||||
|
ctrDepsBkt := ctrExists.Bucket(dependenciesBkt)
|
||||||
|
if ctrDepsBkt == nil {
|
||||||
|
return errors.Wrapf(ErrInternal, "container %s does not have a dependencies bucket", ctr.ID())
|
||||||
|
}
|
||||||
|
deps := []string{}
|
||||||
|
err = ctrDepsBkt.ForEach(func(id, value []byte) error {
|
||||||
|
deps = append(deps, string(id))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(deps) != 0 {
|
||||||
|
return errors.Wrapf(ErrCtrExists, "container %s is a dependency of the following containers: %s", ctr.ID(), strings.Join(deps, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ctrBucket.DeleteBucket(ctrID); err != nil {
|
||||||
|
return errors.Wrapf(ErrInternal, "error deleting container %s from DB", ctr.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := idsBucket.Delete(ctrID); err != nil {
|
||||||
|
return errors.Wrapf(err, "error deleting container %s ID in DB", ctr.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := namesBucket.Delete(ctrName); err != nil {
|
||||||
|
return errors.Wrapf(err, "error deleting container %s name in DB", ctr.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
depCtrs := ctr.Dependencies()
|
||||||
|
|
||||||
|
// Remove us from other container's dependencies
|
||||||
|
for _, depCtr := range depCtrs {
|
||||||
|
depCtrID := []byte(depCtr)
|
||||||
|
|
||||||
|
depCtrBkt := ctrBucket.Bucket(depCtrID)
|
||||||
|
if depCtrBkt == nil {
|
||||||
|
// The dependent container has been removed
|
||||||
|
// This should not be possible, and means the
|
||||||
|
// state is inconsistent, but don't error
|
||||||
|
// The container with inconsistent state is the
|
||||||
|
// one being removed
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
depCtrDependsBkt := depCtrBkt.Bucket(dependenciesBkt)
|
||||||
|
if depCtrDependsBkt == nil {
|
||||||
|
// This is more serious - another container in
|
||||||
|
// the state is inconsistent
|
||||||
|
// Log it, continue removing
|
||||||
|
logrus.Errorf("Container %s is missing dependencies bucket in DB", ctr.ID())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := depCtrDependsBkt.Delete(ctrID); err != nil {
|
||||||
|
return errors.Wrapf(err, "error removing container %s as a dependency of container %s", ctr.ID(), depCtr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -11,13 +11,13 @@ import (
|
|||||||
|
|
||||||
// Pod represents a group of containers that may share namespaces
|
// Pod represents a group of containers that may share namespaces
|
||||||
type Pod struct {
|
type Pod struct {
|
||||||
id string
|
id string `json:"id"`
|
||||||
name string
|
name string `json:"name"`
|
||||||
labels map[string]string
|
labels map[string]string `json:"labels"`
|
||||||
|
|
||||||
valid bool
|
valid bool `json:"-"`
|
||||||
runtime *Runtime
|
runtime *Runtime `json:"-"`
|
||||||
lock storage.Locker
|
lock storage.Locker `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID retrieves the pod's ID
|
// ID retrieves the pod's ID
|
||||||
|
Reference in New Issue
Block a user