aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Heon <matthew.heon@gmail.com>2018-01-15 11:21:30 -0500
committerAtomic Bot <atomic-devel@projectatomic.io>2018-01-15 19:50:59 +0000
commit2e48c60bc5f7eb6b301c696f9e4c1cabaf1ec4aa (patch)
treec2daf7eaa83968f841c0b10ff5cd266eed439f4f
parent2bfb31ddf4b7f28a67ef94b8b318536c367a663b (diff)
downloadpodman-2e48c60bc5f7eb6b301c696f9e4c1cabaf1ec4aa.tar.gz
podman-2e48c60bc5f7eb6b301c696f9e4c1cabaf1ec4aa.tar.bz2
podman-2e48c60bc5f7eb6b301c696f9e4c1cabaf1ec4aa.zip
Add DNS and security fields to DB
Also moves port mappings out of the SQL DB and into a file on disk. These could get very sizable (hundred to thousands of ports) so moving them out to a file will keep the DB small and fast. Finally, add a foreign key reference from container ID to container state ID. This ensures we never get into an inconsistent state where we have data in one table but not the other. Signed-off-by: Matthew Heon <matthew.heon@gmail.com> Closes: #225 Approved by: baude
-rw-r--r--libpod/container.go31
-rw-r--r--libpod/sql_state.go73
-rw-r--r--libpod/sql_state_internal.go101
-rw-r--r--libpod/sql_state_test.go20
4 files changed, 190 insertions, 35 deletions
diff --git a/libpod/container.go b/libpod/container.go
index 2c769b00b..7b0852c07 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -156,23 +156,28 @@ type ContainerConfig struct {
Mounts []string `json:"mounts,omitempty"`
// Security Config
+ // Whether the container is privileged
+ Privileged bool `json:"privileged"`
+ // Whether to set the No New Privileges flag
+ NoNewPrivs bool `json:"noNewPrivs"`
// SELinux process label for container
ProcessLabel string `json:"ProcessLabel,omitempty"`
// SELinux mount label for root filesystem
MountLabel string `json:"MountLabel,omitempty"`
// User and group to use in the container
// Can be specified by name or UID/GID
- User string `json:"user"`
+ User string `json:"user,omitempty"`
// 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"`
+ IPCNsCtr string `json:"ipcNsCtr,omitempty"`
+ MountNsCtr string `json:"mountNsCtr,omitempty"`
+ NetNsCtr string `json:"netNsCtr,omitempty"`
+ PIDNsCtr string `json:"pidNsCtr,omitempty"`
+ UserNsCtr string `json:"userNsCtr,omitempty"`
+ UTSNsCtr string `json:"utsNsCtr,omitempty"`
+ CgroupNsCtr string `json:"cgroupNsCtr,omitempty"`
// Network Config
// CreateNetNS indicates that libpod should create and configure a new
@@ -183,6 +188,18 @@ type ContainerConfig struct {
// namespace
// These are not used unless CreateNetNS is true
PortMappings []ocicni.PortMapping `json:"portMappings,omitempty"`
+ // DNS servers to use in container resolv.conf
+ // Will override servers in host resolv if set
+ DNSServer []net.IP `json:"dnsServer,omitempty"`
+ // DNS Search domains to use in container resolv.conf
+ // Will override search domains in host resolv if set
+ DNSSearch []string `json:"dnsSearch,omitempty"`
+ // DNS options to be set in container resolv.conf
+ // With override options in host resolv if set
+ DNSOption []string `json:"dnsOption,omitempty"`
+ // Hosts to add in container
+ // Will be appended to host's host file
+ HostAdd []string `json:"hostsAdd,omitempty"`
// Misc Options
// Whether to keep container STDIN open
diff --git a/libpod/sql_state.go b/libpod/sql_state.go
index fe3232e62..51ec25510 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 = 7
+const DBSchema = 8
// SQLState is a state implementation backed by a persistent SQLite3 database
type SQLState struct {
@@ -284,7 +284,8 @@ func (s *SQLState) AddContainer(ctr *Container) (err error) {
?, ?, ?, ?, ?,
?, ?, ?, ?, ?,
?, ?, ?, ?, ?,
- ?, ?, ?
+ ?, ?, ?, ?, ?,
+ ?, ?, ?, ?
);`
addCtrState = `INSERT INTO containerState VALUES (
?, ?, ?, ?, ?,
@@ -306,9 +307,24 @@ func (s *SQLState) AddContainer(ctr *Container) (err error) {
return errors.Wrapf(err, "error marshaling container %s mounts to JSON", ctr.ID())
}
- portsJSON, err := json.Marshal(ctr.config.PortMappings)
+ dnsServerJSON, err := json.Marshal(ctr.config.DNSServer)
+ if err != nil {
+ return errors.Wrapf(err, "error marshaling container %s DNS servers to JSON", ctr.ID())
+ }
+
+ dnsSearchJSON, err := json.Marshal(ctr.config.DNSSearch)
+ if err != nil {
+ return errors.Wrapf(err, "error marshaling container %s DNS search domains to JSON", ctr.ID())
+ }
+
+ dnsOptionJSON, err := json.Marshal(ctr.config.DNSOption)
if err != nil {
- return errors.Wrapf(err, "error marshaling container %s port mappings to JSON", ctr.ID())
+ return errors.Wrapf(err, "error marshaling container %s DNS options to JSON", ctr.ID())
+ }
+
+ hostAddJSON, err := json.Marshal(ctr.config.HostAdd)
+ if err != nil {
+ return errors.Wrapf(err, "error marshaling container %s hosts to JSON", ctr.ID())
}
labelsJSON, err := json.Marshal(ctr.config.Labels)
@@ -321,6 +337,19 @@ func (s *SQLState) AddContainer(ctr *Container) (err error) {
netNSPath = ctr.state.NetNS.Path()
}
+ specJSON, err := json.Marshal(ctr.config.Spec)
+ if err != nil {
+ return errors.Wrapf(err, "error marshalling container %s spec to JSON", ctr.ID())
+ }
+
+ portsJSON := []byte{}
+ if len(ctr.config.PortMappings) > 0 {
+ portsJSON, err = json.Marshal(&ctr.config.PortMappings)
+ if err != nil {
+ return errors.Wrapf(err, "error marshalling container %s port mappings to JSON", ctr.ID())
+ }
+ }
+
tx, err := s.db.Begin()
if err != nil {
return errors.Wrapf(err, "error beginning database transaction")
@@ -348,6 +377,8 @@ func (s *SQLState) AddContainer(ctr *Container) (err error) {
ctr.config.StaticDir,
string(mounts),
+ boolToSQL(ctr.config.Privileged),
+ boolToSQL(ctr.config.NoNewPrivs),
ctr.config.ProcessLabel,
ctr.config.MountLabel,
ctr.config.User,
@@ -358,9 +389,13 @@ func (s *SQLState) AddContainer(ctr *Container) (err error) {
stringToNullString(ctr.config.PIDNsCtr),
stringToNullString(ctr.config.UserNsCtr),
stringToNullString(ctr.config.UTSNsCtr),
+ stringToNullString(ctr.config.CgroupNsCtr),
boolToSQL(ctr.config.CreateNetNS),
- string(portsJSON),
+ string(dnsServerJSON),
+ string(dnsSearchJSON),
+ string(dnsOptionJSON),
+ string(hostAddJSON),
boolToSQL(ctr.config.Stdin),
string(labelsJSON),
@@ -392,10 +427,6 @@ func (s *SQLState) AddContainer(ctr *Container) (err error) {
}
// Save the container's runtime spec to disk
- specJSON, err := json.Marshal(ctr.config.Spec)
- if err != nil {
- return errors.Wrapf(err, "error marshalling container %s spec to JSON", ctr.ID())
- }
specPath := getSpecPath(s.specsDir, ctr.ID())
if err := ioutil.WriteFile(specPath, specJSON, 0750); err != nil {
return errors.Wrapf(err, "error saving container %s spec JSON to disk", ctr.ID())
@@ -408,6 +439,21 @@ func (s *SQLState) AddContainer(ctr *Container) (err error) {
}
}()
+ // If the container has port mappings, save them to disk
+ if len(ctr.config.PortMappings) > 0 {
+ portPath := getPortsPath(s.specsDir, ctr.ID())
+ if err := ioutil.WriteFile(portPath, portsJSON, 0750); err != nil {
+ return errors.Wrapf(err, "error saving container %s port JSON to disk", ctr.ID())
+ }
+ defer func() {
+ if err != nil {
+ if err2 := os.Remove(portPath); err2 != nil {
+ logrus.Errorf("Error removing container %s JSON ports from state: %v", ctr.ID(), err2)
+ }
+ }
+ }()
+ }
+
if err := tx.Commit(); err != nil {
return errors.Wrapf(err, "error committing transaction to add container %s", ctr.ID())
}
@@ -668,6 +714,15 @@ func (s *SQLState) RemoveContainer(ctr *Container) error {
return errors.Wrapf(err, "error removing JSON spec from state for container %s", ctr.ID())
}
+ // Remove containers ports JSON from disk
+ // May not exist, so ignore os.IsNotExist
+ portsPath := getPortsPath(s.specsDir, ctr.ID())
+ if err := os.Remove(portsPath); err != nil {
+ if !os.IsNotExist(err) {
+ return errors.Wrapf(err, "error removing JSON ports from state for container %s", ctr.ID())
+ }
+ }
+
ctr.valid = false
return nil
diff --git a/libpod/sql_state_internal.go b/libpod/sql_state_internal.go
index ef3b6bd4e..189fae190 100644
--- a/libpod/sql_state_internal.go
+++ b/libpod/sql_state_internal.go
@@ -4,6 +4,7 @@ import (
"database/sql"
"encoding/json"
"io/ioutil"
+ "os"
"path/filepath"
"time"
@@ -178,6 +179,8 @@ func prepareDB(db *sql.DB) (err error) {
StaticDir TEXT NOT NULL,
Mounts TEXT NOT NULL,
+ Privileged INTEGER NOT NULL,
+ NoNewPrivs INTEGER NOT NULL,
ProcessLabel TEXT NOT NULL,
MountLabel TEXT NOT NULL,
User TEXT NOT NULL,
@@ -188,9 +191,13 @@ func prepareDB(db *sql.DB) (err error) {
PIDNsCtr TEXT,
UserNsCtr TEXT,
UTSNsCtr TEXT,
+ CgroupNsCtr TEXT,
CreateNetNS INTEGER NOT NULL,
- PortMappings TEXT NOT NULL,
+ DNSServer TEXT NOT NULL,
+ DNSSearch TEXT NOT NULL,
+ DNSOption TEXT NOT NULL,
+ HostAdd TEXT NOT NULL,
Stdin INTEGER NOT NULL,
LabelsJSON TEXT NOT NULL,
@@ -202,16 +209,20 @@ func prepareDB(db *sql.DB) (err error) {
CHECK (ImageVolumes IN (0, 1)),
CHECK (ReadOnly IN (0, 1)),
CHECK (SHMSize>=0),
+ CHECK (Privileged IN (0, 1)),
+ CHECK (NoNewPrivs IN (0, 1)),
CHECK (CreateNetNS IN (0, 1)),
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
+ FOREIGN KEY (Id) REFERENCES containerState(Id) DEFERRABLE INITIALLY DEFERRED
+ 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,
+ FOREIGN KEY (CgroupNsCtr) REFERENCES containers(Id) DEFERRABLE INITIALLY DEFERRED
);
`
@@ -283,6 +294,11 @@ func getSpecPath(specsDir, id string) string {
return filepath.Join(specsDir, id)
}
+// Get filename for container port mappings on disk
+func getPortsPath(specsDir, id string) string {
+ return filepath.Join(specsDir, id+"_ports")
+}
+
// Convert a bool into SQL-readable format
func boolToSQL(b bool) int {
if b {
@@ -347,19 +363,25 @@ func (s *SQLState) ctrFromScannable(row scannable) (*Container, error) {
staticDir string
mounts string
+ privileged int
+ noNewPrivs int
processLabel string
mountLabel string
user string
- ipcNsCtrNullStr sql.NullString
- mountNsCtrNullStr sql.NullString
- netNsCtrNullStr sql.NullString
- pidNsCtrNullStr sql.NullString
- userNsCtrNullStr sql.NullString
- utsNsCtrNullStr sql.NullString
+ ipcNsCtrNullStr sql.NullString
+ mountNsCtrNullStr sql.NullString
+ netNsCtrNullStr sql.NullString
+ pidNsCtrNullStr sql.NullString
+ userNsCtrNullStr sql.NullString
+ utsNsCtrNullStr sql.NullString
+ cgroupNsCtrNullStr sql.NullString
- createNetNS int
- portMappingsJSON string
+ createNetNS int
+ dnsServerJSON string
+ dnsSearchJSON string
+ dnsOptionJSON string
+ hostAddJSON string
stdin int
labelsJSON string
@@ -396,6 +418,8 @@ func (s *SQLState) ctrFromScannable(row scannable) (*Container, error) {
&staticDir,
&mounts,
+ &privileged,
+ &noNewPrivs,
&processLabel,
&mountLabel,
&user,
@@ -406,9 +430,13 @@ func (s *SQLState) ctrFromScannable(row scannable) (*Container, error) {
&pidNsCtrNullStr,
&userNsCtrNullStr,
&utsNsCtrNullStr,
+ &cgroupNsCtrNullStr,
&createNetNS,
- &portMappingsJSON,
+ &dnsServerJSON,
+ &dnsSearchJSON,
+ &dnsOptionJSON,
+ &hostAddJSON,
&stdin,
&labelsJSON,
@@ -453,6 +481,8 @@ func (s *SQLState) ctrFromScannable(row scannable) (*Container, error) {
ctr.config.ShmSize = shmSize
ctr.config.StaticDir = staticDir
+ ctr.config.Privileged = boolFromSQL(privileged)
+ ctr.config.NoNewPrivs = boolFromSQL(noNewPrivs)
ctr.config.ProcessLabel = processLabel
ctr.config.MountLabel = mountLabel
ctr.config.User = user
@@ -463,6 +493,7 @@ func (s *SQLState) ctrFromScannable(row scannable) (*Container, error) {
ctr.config.PIDNsCtr = stringFromNullString(pidNsCtrNullStr)
ctr.config.UserNsCtr = stringFromNullString(userNsCtrNullStr)
ctr.config.UTSNsCtr = stringFromNullString(utsNsCtrNullStr)
+ ctr.config.CgroupNsCtr = stringFromNullString(cgroupNsCtrNullStr)
ctr.config.CreateNetNS = boolFromSQL(createNetNS)
@@ -490,8 +521,20 @@ func (s *SQLState) ctrFromScannable(row scannable) (*Container, error) {
return nil, errors.Wrapf(err, "error parsing container %s mounts JSON", id)
}
- if err := json.Unmarshal([]byte(portMappingsJSON), &ctr.config.PortMappings); err != nil {
- return nil, errors.Wrapf(err, "error parsing container %s port mappings JSON", id)
+ if err := json.Unmarshal([]byte(dnsServerJSON), &ctr.config.DNSServer); err != nil {
+ return nil, errors.Wrapf(err, "error parsing container %s DNS server JSON", id)
+ }
+
+ if err := json.Unmarshal([]byte(dnsSearchJSON), &ctr.config.DNSSearch); err != nil {
+ return nil, errors.Wrapf(err, "error parsing container %s DNS search JSON", id)
+ }
+
+ if err := json.Unmarshal([]byte(dnsOptionJSON), &ctr.config.DNSOption); err != nil {
+ return nil, errors.Wrapf(err, "error parsing container %s DNS option JSON", id)
+ }
+
+ if err := json.Unmarshal([]byte(hostAddJSON), &ctr.config.HostAdd); err != nil {
+ return nil, errors.Wrapf(err, "error parsing container %s DNS server JSON", id)
}
labels := make(map[string]string)
@@ -550,5 +593,25 @@ func (s *SQLState) ctrFromScannable(row scannable) (*Container, error) {
}
ctr.config.Spec = ociSpec
+ // Retrieve the ports from disk
+ // They may not exist - if they don't, this container just doesn't have ports
+ portPath := getPortsPath(s.specsDir, id)
+ _, err = os.Stat(portPath)
+ if err != nil {
+ if !os.IsNotExist(err) {
+ return nil, errors.Wrapf(err, "error stating container %s JSON ports", id)
+ }
+ }
+ if err == nil {
+ // The file exists, read it
+ fileContents, err := ioutil.ReadFile(portPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error reading container %s JSON ports", id)
+ }
+ if err := json.Unmarshal(fileContents, &ctr.config.PortMappings); err != nil {
+ return nil, errors.Wrapf(err, "error parsing container %s JSON ports", id)
+ }
+ }
+
return ctr, nil
}
diff --git a/libpod/sql_state_test.go b/libpod/sql_state_test.go
index 020e2ce40..19d5da63e 100644
--- a/libpod/sql_state_test.go
+++ b/libpod/sql_state_test.go
@@ -3,6 +3,7 @@ package libpod
import (
"encoding/json"
"io/ioutil"
+ "net"
"os"
"path/filepath"
"reflect"
@@ -10,6 +11,7 @@ import (
"time"
"github.com/containers/storage"
+ "github.com/cri-o/ocicni/pkg/ocicni"
"github.com/opencontainers/runtime-tools/generate"
"github.com/stretchr/testify/assert"
)
@@ -29,6 +31,24 @@ func getTestContainer(id, name, locksDir string) (*Container, error) {
StopSignal: 0,
StopTimeout: 0,
CreatedTime: time.Now(),
+ Privileged: true,
+ Mounts: []string{"/does/not/exist"},
+ DNSServer: []net.IP{net.ParseIP("192.168.1.1"), net.ParseIP("192.168.2.2")},
+ DNSSearch: []string{"example.com", "example.example.com"},
+ PortMappings: []ocicni.PortMapping{
+ {
+ HostPort: 80,
+ ContainerPort: 90,
+ Protocol: "tcp",
+ HostIP: "192.168.3.3",
+ },
+ {
+ HostPort: 100,
+ ContainerPort: 110,
+ Protocol: "udp",
+ HostIP: "192.168.4.4",
+ },
+ },
},
state: &containerRuntimeInfo{
State: ContainerStateRunning,