aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libpod/container.go92
-rw-r--r--libpod/container_top.go2
-rw-r--r--libpod/options.go4
-rw-r--r--libpod/sql_state.go98
-rw-r--r--libpod/sql_state_internal.go271
-rw-r--r--libpod/sql_state_test.go3
6 files changed, 338 insertions, 132 deletions
diff --git a/libpod/container.go b/libpod/container.go
index 66eb4aa2d..79fd5d42c 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -61,8 +61,8 @@ const (
artifactsDir = "artifacts"
)
-// CGroupParent is the prefix to a cgroup path in libpod
-var CGroupParent = "/libpod_parent"
+// CgroupParent is the default prefix to a cgroup path in libpod
+var CgroupParent = "/libpod_parent"
// Container is a single OCI container
type Container struct {
@@ -78,6 +78,13 @@ type Container struct {
runtime *Runtime
}
+// TODO fetch IP and Subnet Mask from networks once we have updated OCICNI
+// TODO enable pod support
+// TODO Add readonly support
+// TODO add SHM size support
+// TODO add shared namespace support
+// TODO add cgroup parent support
+
// containerRuntimeInfo contains the current state of the container
// It is stored on disk in a tmpfs and recreated on reboot
type containerRuntimeInfo struct {
@@ -107,7 +114,10 @@ type containerRuntimeInfo struct {
// Will only be set if config.CreateNetNS is true, or the container was
// told to join another container's network namespace
NetNS ns.NetNS
- // TODO: Save information about image used in container if one is used
+ // IP address of container (if network namespace was created)
+ IPAddress string
+ // Subnet mask of container (if network namespace was created)
+ SubnetMask string
}
// ContainerConfig contains all information that was used to create the
@@ -117,49 +127,76 @@ type ContainerConfig struct {
Spec *spec.Spec `json:"spec"`
ID string `json:"id"`
Name string `json:"name"`
+ // Full ID of the pood the container belongs to
+ Pod string `json:"pod,omitempty"`
+
+ // TODO consider breaking these subsections up into smaller structs
+
+ // Storage Config
// Information on the image used for the root filesystem
RootfsImageID string `json:"rootfsImageID,omitempty"`
RootfsImageName string `json:"rootfsImageName,omitempty"`
- UseImageConfig bool `json:"useImageConfig"`
+ // Whether to mount volumes specified in the image
+ ImageVolumes bool `json:"imageVolumes"`
+ // Whether to make the container read only
+ ReadOnly bool `json:"readOnly"`
+ // Src path to be mounted on /dev/shm in container
+ ShmDir string `json:"ShmDir,omitempty"`
+ // Size of the container's SHM
+ ShmSize int64 `json:"shmSize"`
+ // Static directory for container content that will persist across
+ // reboot
+ StaticDir string `json:"staticDir"`
+ // Mounts list contains all additional mounts into the container rootfs
+ // These include the SHM mount
+ // These must be unmounted before the container's rootfs is unmounted
+ Mounts []string `json:"mounts,omitempty"`
+
+ // Security Config
// SELinux process label for container
ProcessLabel string `json:"ProcessLabel,omitempty"`
// SELinux mount label for root filesystem
MountLabel string `json:"MountLabel,omitempty"`
- // Src path to be mounted on /dev/shm in container
- ShmDir string `json:"ShmDir,omitempty"`
+ // User and group to use in the container
+ // Can be specified by name or UID/GID
+ User string `json:"user"`
+
+ // Namespace Config
+ // IDs of container to share namespaces with
+ // NetNsCtr conflicts with the CreateNetNS bool
+ IPCNsCtr string `json:"ipcNsCtr"`
+ MountNsCtr string `json:"mountNsCtr"`
+ NetNsCtr string `json:"netNsCtr"`
+ PIDNsCtr string `json:"pidNsCtr"`
+ UserNsCtr string `json:"userNsCtr"`
+ UTSNsCtr string `json:"utsNsCtr"`
+
+ // Network Config
// CreateNetNS indicates that libpod should create and configure a new
// network namespace for the container
+ // This cannot be set if NetNsCtr is also set
CreateNetNS bool `json:"createNetNS"`
// PortMappings are the ports forwarded to the container's network
// namespace
// These are not used unless CreateNetNS is true
- PortMappings []ocicni.PortMapping
- // Static directory for container content that will persist across
- // reboot
- StaticDir string `json:"staticDir"`
+ PortMappings []ocicni.PortMapping `json:"portMappings,omitempty"`
+
+ // Misc Options
// Whether to keep container STDIN open
Stdin bool `json:"stdin,omitempty"`
- // Pod the container belongs to
- Pod string `json:"pod,omitempty"`
// Labels is a set of key-value pairs providing additional information
// about a container
Labels map[string]string `json:"labels,omitempty"`
- // Mounts list contains all additional mounts by the container runtime.
- Mounts []string `json:"mounts,omitempty"`
// StopSignal is the signal that will be used to stop the container
StopSignal uint `json:"stopSignal,omitempty"`
// StopTimeout is the signal that will be used to stop the container
StopTimeout uint `json:"stopTimeout,omitempty"`
- // Shared namespaces with container
- SharedNamespaceCtr *string `json:"shareNamespacesWith,omitempty"`
- SharedNamespaceMap map[string]string `json:"sharedNamespaces"`
// Time container was created
CreatedTime time.Time `json:"createdTime"`
- // User/GID to use within the container
- User string `json:"user"`
+ // Cgroup parent of the container
+ CgroupParent string `json:"cgroupParent"`
- // TODO save log location here and pass into OCI code
- // TODO allow overriding of log path
+ // TODO log options - logpath for plaintext, others for log drivers
}
// ContainerStater returns a string representation for users
@@ -192,6 +229,12 @@ func (c *Container) Name() string {
return c.config.Name
}
+// PodID returns the full ID of the pod the container belongs to, or "" if it
+// does not belong to a pod
+func (c *Container) PodID() string {
+ return c.config.Pod
+}
+
// ShmDir returns the sources path to be mounted on /dev/shm in container
func (c *Container) ShmDir() string {
return c.config.ShmDir
@@ -468,6 +511,9 @@ func newContainer(rspec *spec.Spec, lockDir string) (*Container, error) {
deepcopier.Copy(rspec).To(ctr.config.Spec)
ctr.config.CreatedTime = time.Now()
+ ctr.config.ShmSize = DefaultShmSize
+ ctr.config.CgroupParent = CgroupParent
+
// Path our lock file will reside at
lockPath := filepath.Join(lockDir, ctr.config.ID)
// Grab a lockfile at the given path
@@ -679,7 +725,7 @@ func (c *Container) Init() (err error) {
// With the spec complete, do an OCI create
// TODO set cgroup parent in a sane fashion
- if err := c.runtime.ociRuntime.createContainer(c, CGroupParent); err != nil {
+ if err := c.runtime.ociRuntime.createContainer(c, CgroupParent); err != nil {
return err
}
@@ -1182,7 +1228,7 @@ func (c *Container) cleanupStorage() error {
// CGroupPath returns a cgroups "path" for a given container.
func (c *Container) CGroupPath() cgroups.Path {
- return cgroups.StaticPath(filepath.Join(CGroupParent, fmt.Sprintf("libpod-conmon-%s", c.ID())))
+ return cgroups.StaticPath(filepath.Join(CgroupParent, fmt.Sprintf("libpod-conmon-%s", c.ID())))
}
// copyHostFileToRundir copies the provided file to the runtimedir
diff --git a/libpod/container_top.go b/libpod/container_top.go
index 7d6dad2b4..020773488 100644
--- a/libpod/container_top.go
+++ b/libpod/container_top.go
@@ -25,7 +25,7 @@ func (c *Container) GetContainerPids() ([]string, error) {
// Gets the pids for a container without locking. should only be called from a func where
// locking has already been established.
func (c *Container) getContainerPids() ([]string, error) {
- taskFile := filepath.Join("/sys/fs/cgroup/pids", CGroupParent, fmt.Sprintf("libpod-conmon-%s", c.ID()), c.ID(), "tasks")
+ taskFile := filepath.Join("/sys/fs/cgroup/pids", CgroupParent, fmt.Sprintf("libpod-conmon-%s", c.ID()), c.ID(), "tasks")
logrus.Debug("reading pids from ", taskFile)
content, err := ioutil.ReadFile(taskFile)
if err != nil {
diff --git a/libpod/options.go b/libpod/options.go
index 0ddbeae55..199bf9ee9 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -325,7 +325,7 @@ func WithUser(user string) CtrCreateOption {
// If useImageConfig is specified, image volumes, environment variables, and
// other configuration from the image will be added to the config
// TODO: Replace image name and ID with a libpod.Image struct when that is finished
-func WithRootFSFromImage(imageID string, imageName string, useImageConfig bool) CtrCreateOption {
+func WithRootFSFromImage(imageID string, imageName string, useImageVolumes bool) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return ErrCtrFinalized
@@ -337,7 +337,7 @@ func WithRootFSFromImage(imageID string, imageName string, useImageConfig bool)
ctr.config.RootfsImageID = imageID
ctr.config.RootfsImageName = imageName
- ctr.config.UseImageConfig = useImageConfig
+ ctr.config.ImageVolumes = useImageVolumes
return nil
}
diff --git a/libpod/sql_state.go b/libpod/sql_state.go
index 42fac831b..fe3232e62 100644
--- a/libpod/sql_state.go
+++ b/libpod/sql_state.go
@@ -15,7 +15,7 @@ import (
// DBSchema is the current DB schema version
// Increments every time a change is made to the database's tables
-const DBSchema = 6
+const DBSchema = 7
// SQLState is a state implementation backed by a persistent SQLite3 database
type SQLState struct {
@@ -104,7 +104,9 @@ func (s *SQLState) Refresh() (err error) {
State=?,
Mountpoint=?,
Pid=?,
- NetNSPath=?;`
+ NetNSPath=?,
+ IPAddress=?,
+ SubnetMask=?;`
if !s.valid {
return ErrDBClosed
@@ -130,6 +132,8 @@ func (s *SQLState) Refresh() (err error) {
ContainerStateConfigured,
"",
0,
+ "",
+ "",
"")
if err != nil {
return errors.Wrapf(err, "error refreshing database state")
@@ -154,7 +158,9 @@ func (s *SQLState) Container(id string) (*Container, error) {
containerState.ExitCode,
containerState.OomKilled,
containerState.Pid,
- containerState.NetNSPath
+ containerState.NetNSPath,
+ containerState.IPAddress,
+ containerState.SubnetMask
FROM containers
INNER JOIN
containerState ON containers.Id = containerState.Id
@@ -170,7 +176,7 @@ func (s *SQLState) Container(id string) (*Container, error) {
row := s.db.QueryRow(query, id)
- ctr, err := ctrFromScannable(row, s.runtime, s.specsDir, s.lockDir)
+ ctr, err := s.ctrFromScannable(row)
if err != nil {
return nil, errors.Wrapf(err, "error retrieving container %s from database", id)
}
@@ -190,7 +196,9 @@ func (s *SQLState) LookupContainer(idOrName string) (*Container, error) {
containerState.ExitCode,
containerState.OomKilled,
containerState.Pid,
- containerState.NetNSPath
+ containerState.NetNSPath,
+ containerState.IPAddress,
+ containerState.SubnetMask
FROM containers
INNER JOIN
containerState ON containers.Id = containerState.Id
@@ -218,7 +226,7 @@ func (s *SQLState) LookupContainer(idOrName string) (*Container, error) {
}
var err error
- ctr, err = ctrFromScannable(rows, s.runtime, s.specsDir, s.lockDir)
+ ctr, err = s.ctrFromScannable(rows)
if err != nil {
return nil, errors.Wrapf(err, "error retrieving container %s from database", idOrName)
}
@@ -271,10 +279,17 @@ func (s *SQLState) HasContainer(id string) (bool, error) {
func (s *SQLState) AddContainer(ctr *Container) (err error) {
const (
addCtr = `INSERT INTO containers VALUES (
- ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
+ ?, ?, ?, ?, ?,
+ ?, ?, ?, ?, ?,
+ ?, ?, ?, ?, ?,
+ ?, ?, ?, ?, ?,
+ ?, ?, ?, ?, ?,
+ ?, ?, ?
);`
addCtrState = `INSERT INTO containerState VALUES (
- ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
+ ?, ?, ?, ?, ?,
+ ?, ?, ?, ?, ?,
+ ?, ?, ?
);`
)
@@ -286,11 +301,6 @@ func (s *SQLState) AddContainer(ctr *Container) (err error) {
return ErrCtrRemoved
}
- labelsJSON, err := json.Marshal(ctr.config.Labels)
- if err != nil {
- return errors.Wrapf(err, "error marshaling container %s labels to JSON", ctr.ID())
- }
-
mounts, err := json.Marshal(ctr.config.Mounts)
if err != nil {
return errors.Wrapf(err, "error marshaling container %s mounts to JSON", ctr.ID())
@@ -301,6 +311,11 @@ func (s *SQLState) AddContainer(ctr *Container) (err error) {
return errors.Wrapf(err, "error marshaling container %s port mappings to JSON", ctr.ID())
}
+ labelsJSON, err := json.Marshal(ctr.config.Labels)
+ if err != nil {
+ return errors.Wrapf(err, "error marshaling container %s labels to JSON", ctr.ID())
+ }
+
netNSPath := ""
if ctr.state.NetNS != nil {
netNSPath = ctr.state.NetNS.Path()
@@ -322,22 +337,37 @@ func (s *SQLState) AddContainer(ctr *Container) (err error) {
_, err = tx.Exec(addCtr,
ctr.ID(),
ctr.Name(),
+ stringToNullString(ctr.PodID()),
+
+ ctr.config.RootfsImageID,
+ ctr.config.RootfsImageName,
+ boolToSQL(ctr.config.ImageVolumes),
+ boolToSQL(ctr.config.ReadOnly),
+ ctr.config.ShmDir,
+ ctr.config.ShmSize,
+ ctr.config.StaticDir,
+ string(mounts),
+
ctr.config.ProcessLabel,
ctr.config.MountLabel,
- string(mounts),
- ctr.config.ShmDir,
+ ctr.config.User,
+
+ stringToNullString(ctr.config.IPCNsCtr),
+ stringToNullString(ctr.config.MountNsCtr),
+ stringToNullString(ctr.config.NetNsCtr),
+ stringToNullString(ctr.config.PIDNsCtr),
+ stringToNullString(ctr.config.UserNsCtr),
+ stringToNullString(ctr.config.UTSNsCtr),
+
boolToSQL(ctr.config.CreateNetNS),
string(portsJSON),
- ctr.config.StaticDir,
+
boolToSQL(ctr.config.Stdin),
string(labelsJSON),
ctr.config.StopSignal,
ctr.config.StopTimeout,
timeToSQL(ctr.config.CreatedTime),
- ctr.config.RootfsImageID,
- ctr.config.RootfsImageName,
- boolToSQL(ctr.config.UseImageConfig),
- ctr.config.User)
+ ctr.config.CgroupParent)
if err != nil {
return errors.Wrapf(err, "error adding static information for container %s to database", ctr.ID())
}
@@ -354,7 +384,9 @@ func (s *SQLState) AddContainer(ctr *Container) (err error) {
ctr.state.ExitCode,
boolToSQL(ctr.state.OOMKilled),
ctr.state.PID,
- netNSPath)
+ netNSPath,
+ ctr.state.IPAddress,
+ ctr.state.SubnetMask)
if err != nil {
return errors.Wrapf(err, "error adding container %s state to database", ctr.ID())
}
@@ -394,7 +426,9 @@ func (s *SQLState) UpdateContainer(ctr *Container) error {
ExitCode,
OomKilled,
Pid,
- NetNSPath
+ NetNSPath,
+ IPAddress,
+ SubnetMask
FROM containerState WHERE ID=?;`
var (
@@ -408,6 +442,8 @@ func (s *SQLState) UpdateContainer(ctr *Container) error {
oomKilled int
pid int
netNSPath string
+ ipAddress string
+ subnetMask string
)
if !s.valid {
@@ -429,7 +465,9 @@ func (s *SQLState) UpdateContainer(ctr *Container) error {
&exitCode,
&oomKilled,
&pid,
- &netNSPath)
+ &netNSPath,
+ &ipAddress,
+ &subnetMask)
if err != nil {
// The container may not exist in the database
if err == sql.ErrNoRows {
@@ -451,6 +489,8 @@ func (s *SQLState) UpdateContainer(ctr *Container) error {
newState.ExitCode = exitCode
newState.OOMKilled = boolFromSQL(oomKilled)
newState.PID = pid
+ newState.IPAddress = ipAddress
+ newState.SubnetMask = subnetMask
if newState.Mountpoint != "" {
newState.Mounted = true
@@ -512,7 +552,9 @@ func (s *SQLState) SaveContainer(ctr *Container) error {
ExitCode=?,
OomKilled=?,
Pid=?,
- NetNSPath=?
+ NetNSPath=?,
+ IPAddress=?,
+ SubnetMask=?
WHERE Id=?;`
if !ctr.valid {
@@ -552,6 +594,8 @@ func (s *SQLState) SaveContainer(ctr *Container) error {
boolToSQL(ctr.state.OOMKilled),
ctr.state.PID,
netNSPath,
+ ctr.state.IPAddress,
+ ctr.state.SubnetMask,
ctr.ID())
if err != nil {
return errors.Wrapf(err, "error updating container %s state in database", ctr.ID())
@@ -642,7 +686,9 @@ func (s *SQLState) AllContainers() ([]*Container, error) {
containerState.ExitCode,
containerState.OomKilled,
containerState.Pid,
- containerState.NetNSPath
+ containerState.NetNSPath,
+ containerState.IPAddress,
+ containerState.SubnetMask
FROM containers
INNER JOIN
containerState ON containers.Id = containerState.Id
@@ -661,7 +707,7 @@ func (s *SQLState) AllContainers() ([]*Container, error) {
containers := []*Container{}
for rows.Next() {
- ctr, err := ctrFromScannable(rows, s.runtime, s.specsDir, s.lockDir)
+ ctr, err := s.ctrFromScannable(rows)
if err != nil {
return nil, err
}
diff --git a/libpod/sql_state_internal.go b/libpod/sql_state_internal.go
index 5904f4254..ef3b6bd4e 100644
--- a/libpod/sql_state_internal.go
+++ b/libpod/sql_state_internal.go
@@ -22,13 +22,13 @@ func checkDB(db *sql.DB, r *Runtime) (err error) {
// TODO: Include UID/GID mappings
const runtimeTable = `
CREATE TABLE runtime(
- Id INTEGER NOT NULL PRIMARY KEY,
- SchemaVersion INTEGER NOT NULL,
- StaticDir TEXT NOT NULL,
- TmpDir TEXT NOT NULL,
- RunRoot TEXT NOT NULL,
- GraphRoot TEXT NOT NULL,
- GraphDriverName TEXT NOT NULL,
+ Id INTEGER NOT NULL PRIMARY KEY,
+ SchemaVersion INTEGER NOT NULL,
+ StaticDir TEXT NOT NULL,
+ TmpDir TEXT NOT NULL,
+ RunRoot TEXT NOT NULL,
+ GraphRoot TEXT NOT NULL,
+ GraphDriverName TEXT NOT NULL,
CHECK (Id=0)
);
`
@@ -155,6 +155,7 @@ func prepareDB(db *sql.DB) (err error) {
// TODO add ctr shared namespaces information - A separate table, probably? So we can FOREIGN KEY the ID
// TODO schema migration might be necessary and should be handled here
// TODO maybe make a port mappings table instead of JSONing the array and storing it?
+ // TODO prepared statements for common queries for performance
// Enable foreign keys in SQLite
if _, err := db.Exec("PRAGMA foreign_keys = ON;"); err != nil {
@@ -164,51 +165,88 @@ func prepareDB(db *sql.DB) (err error) {
// Create a table for unchanging container data
const createCtr = `
CREATE TABLE IF NOT EXISTS containers(
- Id TEXT NOT NULL PRIMARY KEY,
- Name TEXT NOT NULL UNIQUE,
- ProcessLabel TEXT NOT NULL,
- MountLabel TEXT NOT NULL,
- Mounts TEXT NOT NULL,
- ShmDir TEXT NOT NULL,
- CreateNetNS INTEGER NOT NULL,
- PortMappings TEXT NOT NULL,
- StaticDir TEXT NOT NULL,
- Stdin INTEGER NOT NULL,
- LabelsJSON TEXT NOT NULL,
- StopSignal INTEGER NOT NULL,
- StopTimeout INTEGER NOT NULL,
- CreatedTime TEXT NOT NULL,
- RootfsImageID TEXT NOT NULL,
- RootfsImageName TEXT NOT NULL,
- UseImageConfig INTEGER NOT NULL,
- User TEXT NOT NULL,
- CHECK (Stdin IN (0, 1)),
+ Id TEXT NOT NULL PRIMARY KEY,
+ Name TEXT NOT NULL UNIQUE,
+ Pod TEXT,
+
+ RootfsImageID TEXT NOT NULL,
+ RootfsImageName TEXT NOT NULL,
+ ImageVolumes INTEGER NOT NULL,
+ ReadOnly INTEGER NOT NULL,
+ ShmDir TEXT NOT NULL,
+ ShmSize INTEGER NOT NULL,
+ StaticDir TEXT NOT NULL,
+ Mounts TEXT NOT NULL,
+
+ ProcessLabel TEXT NOT NULL,
+ MountLabel TEXT NOT NULL,
+ User TEXT NOT NULL,
+
+ IPCNsCtr TEXT,
+ MountNsCtr TEXT,
+ NetNsCtr TEXT,
+ PIDNsCtr TEXT,
+ UserNsCtr TEXT,
+ UTSNsCtr TEXT,
+
+ CreateNetNS INTEGER NOT NULL,
+ PortMappings TEXT NOT NULL,
+
+ Stdin INTEGER NOT NULL,
+ LabelsJSON TEXT NOT NULL,
+ StopSignal INTEGER NOT NULL,
+ StopTimeout INTEGER NOT NULL,
+ CreatedTime TEXT NOT NULL,
+ CgroupParent TEXT NOT NULL,
+
+ CHECK (ImageVolumes IN (0, 1)),
+ CHECK (ReadOnly IN (0, 1)),
+ CHECK (SHMSize>=0),
CHECK (CreateNetNS IN (0, 1)),
- CHECK (UseImageConfig IN (0, 1)),
- CHECK (StopSignal>=0)
+ CHECK (Stdin IN (0, 1)),
+ CHECK (StopSignal>=0),
+ FOREIGN KEY (Pod) REFERENCES pod(Id) DEFERRABLE INITIALLY DEFERRED,
+ FOREIGN KEY (IPCNsCtr) REFERENCES containers(Id) DEFERRABLE INITIALLY DEFERRED,
+ FOREIGN KEY (MountNsCtr) REFERENCES containers(Id) DEFERRABLE INITIALLY DEFERRED,
+ FOREIGN KEY (NetNsCtr) REFERENCES containers(Id) DEFERRABLE INITIALLY DEFERRED,
+ FOREIGN KEY (PIDNsCtr) REFERENCES containers(Id) DEFERRABLE INITIALLY DEFERRED,
+ FOREIGN KEY (UserNsCtr) REFERENCES containers(Id) DEFERRABLE INITIALLY DEFERRED,
+ FOREIGN KEY (UTSNsCtr) REFERENCES containers(Id) DEFERRABLE INITIALLY DEFERRED
);
`
// Create a table for changing container state
const createCtrState = `
CREATE TABLE IF NOT EXISTS containerState(
- Id TEXT NOT NULL PRIMARY KEY,
- State INTEGER NOT NULL,
- ConfigPath TEXT NOT NULL,
- RunDir TEXT NOT NULL,
- Mountpoint TEXT NOT NULL,
- StartedTime TEXT NUT NULL,
- FinishedTime TEXT NOT NULL,
- ExitCode INTEGER NOT NULL,
- OomKilled INTEGER NOT NULL,
- Pid INTEGER NOT NULL,
- NetNSPath TEXT NOT NULL,
+ Id TEXT NOT NULL PRIMARY KEY,
+ State INTEGER NOT NULL,
+ ConfigPath TEXT NOT NULL,
+ RunDir TEXT NOT NULL,
+ Mountpoint TEXT NOT NULL,
+ StartedTime TEXT NUT NULL,
+ FinishedTime TEXT NOT NULL,
+ ExitCode INTEGER NOT NULL,
+ OomKilled INTEGER NOT NULL,
+ Pid INTEGER NOT NULL,
+ NetNSPath TEXT NOT NULL,
+ IPAddress TEXT NOT NULL,
+ SubnetMask TEXT NOT NULL,
+
CHECK (State>0),
CHECK (OomKilled IN (0, 1)),
FOREIGN KEY (Id) REFERENCES containers(Id) DEFERRABLE INITIALLY DEFERRED
);
`
+ // Create a table for pod config
+ const createPod = `
+ CREATE TABLE IF NOT EXISTS pod(
+ Id TEXT NOT NULL PRIMARY KEY,
+ Name TEXT NOT NULL UNIQUE,
+ Labels TEXT NOT NULL
+ );
+ `
+
// Create the tables
tx, err := db.Begin()
if err != nil {
@@ -229,6 +267,9 @@ func prepareDB(db *sql.DB) (err error) {
if _, err := tx.Exec(createCtrState); err != nil {
return errors.Wrapf(err, "error creating container state table in database")
}
+ if _, err := tx.Exec(createPod); err != nil {
+ return errors.Wrapf(err, "error creating pods table in database")
+ }
if err := tx.Commit(); err != nil {
return errors.Wrapf(err, "error committing table creation transaction in database")
@@ -251,6 +292,25 @@ func boolToSQL(b bool) int {
return 0
}
+// Convert a null string from SQL-readable format
+func stringFromNullString(s sql.NullString) string {
+ if s.Valid {
+ return s.String
+ }
+ return ""
+}
+
+// Convert a string to a SQL nullable string
+func stringToNullString(s string) sql.NullString {
+ if s == "" {
+ return sql.NullString{}
+ }
+ return sql.NullString{
+ String: s,
+ Valid: true,
+ }
+}
+
// Convert a bool from SQL-readable format
func boolFromSQL(i int) bool {
return i != 0
@@ -272,26 +332,42 @@ type scannable interface {
}
// Read a single container from a single row result in the database
-func ctrFromScannable(row scannable, runtime *Runtime, specsDir string, lockDir string) (*Container, error) {
+func (s *SQLState) ctrFromScannable(row scannable) (*Container, error) {
var (
- id string
- name string
- processLabel string
- mountLabel string
- mounts string
- shmDir string
- createNetNS int
- portMappingsJSON string
- staticDir string
- stdin int
- labelsJSON string
- stopSignal uint
- stopTimeout uint
- createdTimeString string
- rootfsImageID string
- rootfsImageName string
- useImageConfig int
- user string
+ id string
+ name string
+ pod sql.NullString
+
+ rootfsImageID string
+ rootfsImageName string
+ imageVolumes int
+ readOnly int
+ shmDir string
+ shmSize int64
+ staticDir string
+ mounts string
+
+ processLabel string
+ mountLabel string
+ user string
+
+ ipcNsCtrNullStr sql.NullString
+ mountNsCtrNullStr sql.NullString
+ netNsCtrNullStr sql.NullString
+ pidNsCtrNullStr sql.NullString
+ userNsCtrNullStr sql.NullString
+ utsNsCtrNullStr sql.NullString
+
+ createNetNS int
+ portMappingsJSON string
+
+ stdin int
+ labelsJSON string
+ stopSignal uint
+ stopTimeout uint
+ createdTimeString string
+ cgroupParent string
+
state int
configPath string
runDir string
@@ -302,27 +378,45 @@ func ctrFromScannable(row scannable, runtime *Runtime, specsDir string, lockDir
oomKilled int
pid int
netNSPath string
+ ipAddress string
+ subnetMask string
)
err := row.Scan(
&id,
&name,
+ &pod,
+
+ &rootfsImageID,
+ &rootfsImageName,
+ &imageVolumes,
+ &readOnly,
+ &shmDir,
+ &shmSize,
+ &staticDir,
+ &mounts,
+
&processLabel,
&mountLabel,
- &mounts,
- &shmDir,
+ &user,
+
+ &ipcNsCtrNullStr,
+ &mountNsCtrNullStr,
+ &netNsCtrNullStr,
+ &pidNsCtrNullStr,
+ &userNsCtrNullStr,
+ &utsNsCtrNullStr,
+
&createNetNS,
&portMappingsJSON,
- &staticDir,
+
&stdin,
&labelsJSON,
&stopSignal,
&stopTimeout,
&createdTimeString,
- &rootfsImageID,
- &rootfsImageName,
- &useImageConfig,
- &user,
+ &cgroupParent,
+
&state,
&configPath,
&runDir,
@@ -332,7 +426,9 @@ func ctrFromScannable(row scannable, runtime *Runtime, specsDir string, lockDir
&exitCode,
&oomKilled,
&pid,
- &netNSPath)
+ &netNSPath,
+ &ipAddress,
+ &subnetMask)
if err != nil {
if err == sql.ErrNoRows {
return nil, ErrNoSuchCtr
@@ -347,18 +443,33 @@ func ctrFromScannable(row scannable, runtime *Runtime, specsDir string, lockDir
ctr.config.ID = id
ctr.config.Name = name
+ ctr.config.Pod = stringFromNullString(pod)
+
ctr.config.RootfsImageID = rootfsImageID
ctr.config.RootfsImageName = rootfsImageName
- ctr.config.UseImageConfig = boolFromSQL(useImageConfig)
+ ctr.config.ImageVolumes = boolFromSQL(imageVolumes)
+ ctr.config.ReadOnly = boolFromSQL(readOnly)
+ ctr.config.ShmDir = shmDir
+ ctr.config.ShmSize = shmSize
+ ctr.config.StaticDir = staticDir
+
ctr.config.ProcessLabel = processLabel
ctr.config.MountLabel = mountLabel
- ctr.config.ShmDir = shmDir
+ ctr.config.User = user
+
+ ctr.config.IPCNsCtr = stringFromNullString(ipcNsCtrNullStr)
+ ctr.config.MountNsCtr = stringFromNullString(mountNsCtrNullStr)
+ ctr.config.NetNsCtr = stringFromNullString(netNsCtrNullStr)
+ ctr.config.PIDNsCtr = stringFromNullString(pidNsCtrNullStr)
+ ctr.config.UserNsCtr = stringFromNullString(userNsCtrNullStr)
+ ctr.config.UTSNsCtr = stringFromNullString(utsNsCtrNullStr)
+
ctr.config.CreateNetNS = boolFromSQL(createNetNS)
- ctr.config.StaticDir = staticDir
+
ctr.config.Stdin = boolFromSQL(stdin)
ctr.config.StopSignal = stopSignal
ctr.config.StopTimeout = stopTimeout
- ctr.config.User = user
+ ctr.config.CgroupParent = cgroupParent
ctr.state.State = ContainerState(state)
ctr.state.ConfigPath = configPath
@@ -367,18 +478,14 @@ func ctrFromScannable(row scannable, runtime *Runtime, specsDir string, lockDir
ctr.state.ExitCode = exitCode
ctr.state.OOMKilled = boolFromSQL(oomKilled)
ctr.state.PID = pid
+ ctr.state.IPAddress = ipAddress
+ ctr.state.SubnetMask = subnetMask
// TODO should we store this in the database separately instead?
if ctr.state.Mountpoint != "" {
ctr.state.Mounted = true
}
- labels := make(map[string]string)
- if err := json.Unmarshal([]byte(labelsJSON), &labels); err != nil {
- return nil, errors.Wrapf(err, "error parsing container %s labels JSON", id)
- }
- ctr.config.Labels = labels
-
if err := json.Unmarshal([]byte(mounts), &ctr.config.Mounts); err != nil {
return nil, errors.Wrapf(err, "error parsing container %s mounts JSON", id)
}
@@ -387,6 +494,12 @@ func ctrFromScannable(row scannable, runtime *Runtime, specsDir string, lockDir
return nil, errors.Wrapf(err, "error parsing container %s port mappings JSON", id)
}
+ labels := make(map[string]string)
+ if err := json.Unmarshal([]byte(labelsJSON), &labels); err != nil {
+ return nil, errors.Wrapf(err, "error parsing container %s labels JSON", id)
+ }
+ ctr.config.Labels = labels
+
createdTime, err := timeFromSQL(createdTimeString)
if err != nil {
return nil, errors.Wrapf(err, "error parsing container %s created time", id)
@@ -415,10 +528,10 @@ func ctrFromScannable(row scannable, runtime *Runtime, specsDir string, lockDir
}
ctr.valid = true
- ctr.runtime = runtime
+ ctr.runtime = s.runtime
// Open and set the lockfile
- lockPath := filepath.Join(lockDir, id)
+ lockPath := filepath.Join(s.lockDir, id)
lock, err := storage.GetLockfile(lockPath)
if err != nil {
return nil, errors.Wrapf(err, "error retrieving lockfile for container %s", id)
@@ -427,7 +540,7 @@ func ctrFromScannable(row scannable, runtime *Runtime, specsDir string, lockDir
// Retrieve the spec from disk
ociSpec := new(spec.Spec)
- specPath := getSpecPath(specsDir, id)
+ specPath := getSpecPath(s.specsDir, id)
fileContents, err := ioutil.ReadFile(specPath)
if err != nil {
return nil, errors.Wrapf(err, "error reading container %s OCI spec", id)
diff --git a/libpod/sql_state_test.go b/libpod/sql_state_test.go
index e990df6c9..020e2ce40 100644
--- a/libpod/sql_state_test.go
+++ b/libpod/sql_state_test.go
@@ -21,7 +21,8 @@ func getTestContainer(id, name, locksDir string) (*Container, error) {
Name: name,
RootfsImageID: id,
RootfsImageName: "testimg",
- UseImageConfig: true,
+ ImageVolumes: true,
+ ReadOnly: true,
StaticDir: "/does/not/exist/",
Stdin: true,
Labels: make(map[string]string),