aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libpod/boltdb_state.go44
-rw-r--r--libpod/in_memory_state.go20
-rw-r--r--libpod/state.go9
-rw-r--r--libpod/state_test.go36
4 files changed, 109 insertions, 0 deletions
diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go
index 104ec78e9..6214333b9 100644
--- a/libpod/boltdb_state.go
+++ b/libpod/boltdb_state.go
@@ -827,6 +827,50 @@ func (s *BoltState) RewriteContainerConfig(ctr *Container, newCfg *ContainerConf
return err
}
+// RewritePodConfig rewrites a pod's configuration.
+// WARNING: This function is DANGEROUS. Do not use without reading the full
+// comment on this function in state.go.
+func (s *BoltState) RewritePodConfig(pod *Pod, newCfg *PodConfig) error {
+ if !s.valid {
+ return ErrDBClosed
+ }
+
+ if !pod.valid {
+ return ErrPodRemoved
+ }
+
+ newCfgJSON, err := json.Marshal(newCfg)
+ if err != nil {
+ return errors.Wrapf(err, "error marshalling new configuration JSON for container %s", pod.ID())
+ }
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return err
+ }
+ defer s.closeDBCon(db)
+
+ err = db.Update(func(tx *bolt.Tx) error {
+ podBkt, err := getPodBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ podDB := podBkt.Bucket([]byte(pod.ID()))
+ if podDB == nil {
+ pod.valid = false
+ return errors.Wrapf(ErrNoSuchPod, "no pod with ID %s found in DB", pod.ID())
+ }
+
+ if err := podDB.Put(configKey, newCfgJSON); err != nil {
+ return errors.Wrapf(err, "error updating pod %s config JSON", pod.ID())
+ }
+
+ return nil
+ })
+ return err
+}
+
// Pod retrieves a pod given its full ID
func (s *BoltState) Pod(id string) (*Pod, error) {
if id == "" {
diff --git a/libpod/in_memory_state.go b/libpod/in_memory_state.go
index 2f8fafa39..ab4fc8ba7 100644
--- a/libpod/in_memory_state.go
+++ b/libpod/in_memory_state.go
@@ -410,6 +410,26 @@ func (s *InMemoryState) RewriteContainerConfig(ctr *Container, newCfg *Container
return nil
}
+// RewritePodConfig rewrites a pod's configuration.
+// This function is DANGEROUS, even with in-memory state.
+// Please read the full comment on it in state.go before using it.
+func (s *InMemoryState) RewritePodConfig(pod *Pod, newCfg *PodConfig) error {
+ if !pod.valid {
+ return ErrPodRemoved
+ }
+
+ // If the pod does not exist, return error
+ statePod, ok := s.pods[pod.ID()]
+ if !ok {
+ pod.valid = false
+ return errors.Wrapf(ErrNoSuchPod, "pod with ID %s not found in state", pod.ID())
+ }
+
+ statePod.config = newCfg
+
+ return nil
+}
+
// Volume retrieves a volume from its full name
func (s *InMemoryState) Volume(name string) (*Volume, error) {
if name == "" {
diff --git a/libpod/state.go b/libpod/state.go
index 42dbe9cc1..98282fc83 100644
--- a/libpod/state.go
+++ b/libpod/state.go
@@ -107,10 +107,19 @@ type State interface {
// newer, but identical, configuration fields), or during libpod init
// WHILE HOLDING THE ALIVE LOCK (to prevent other libpod instances from
// being initialized).
+ // Most things in config can be changed by this, but container ID and
+ // name ABSOLUTELY CANNOT BE ALTERED. If you do so, there is a high
+ // potential for database corruption.
// There are a lot of capital letters and conditions here, but the short
// answer is this: use this only very sparingly, and only if you really
// know what you're doing.
RewriteContainerConfig(ctr *Container, newCfg *ContainerConfig) error
+ // PLEASE READ THE ABOVE DESCRIPTION BEFORE USING.
+ // This function is identical to RewriteContainerConfig, save for the
+ // fact that it is used with pods instead.
+ // It is subject to the same conditions as RewriteContainerConfig.
+ // Please do not use this unless you know what you're doing.
+ RewritePodConfig(pod *Pod, newCfg *PodConfig) error
// Accepts full ID of pod.
// If the pod given is not in the set namespace, an error will be
diff --git a/libpod/state_test.go b/libpod/state_test.go
index dd03903ac..be68a2d69 100644
--- a/libpod/state_test.go
+++ b/libpod/state_test.go
@@ -1334,6 +1334,42 @@ func TestRewriteContainerConfigRewritesConfig(t *testing.T) {
})
}
+func TestRewritePodConfigDoesNotExist(t *testing.T) {
+ runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
+ err := state.RewritePodConfig(&Pod{}, &PodConfig{})
+ assert.Error(t, err)
+ })
+}
+
+func TestRewritePodConfigNotInState(t *testing.T) {
+ runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
+ testPod, err := getTestPod1(manager)
+ assert.NoError(t, err)
+ err = state.RewritePodConfig(testPod, &PodConfig{})
+ assert.Error(t, err)
+ })
+}
+
+func TestRewritePodConfigRewritesConfig(t *testing.T) {
+ runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
+ testPod, err := getTestPod1(manager)
+ assert.NoError(t, err)
+
+ err = state.AddPod(testPod)
+ assert.NoError(t, err)
+
+ testPod.config.CgroupParent = "/another_cgroup_parent"
+
+ err = state.RewritePodConfig(testPod, testPod.config)
+ assert.NoError(t, err)
+
+ testPodFromState, err := state.Pod(testPod.ID())
+ assert.NoError(t, err)
+
+ testPodsEqual(t, testPodFromState, testPod, true)
+ })
+}
+
func TestGetPodDoesNotExist(t *testing.T) {
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
_, err := state.Pod("doesnotexist")