diff --git a/internal/pkg/containerized/proxy.go b/internal/pkg/containerized/proxy.go new file mode 100644 index 0000000000..ed195db316 --- /dev/null +++ b/internal/pkg/containerized/proxy.go @@ -0,0 +1,66 @@ +package containerized + +import ( + "encoding/json" + "io/ioutil" + "os" + "path/filepath" +) + +var ( + proxydir = "/etc/containerd-proxy" +) + +type proxyConfig struct { + ID string `json:"-"` + Namespace string `json:"namespace"` + Image string `json:"image"` + ImagePath string `json:"imagePath"` + Args []string `json:"args"` + Scope string `json:"scope"` +} + +func updateConfig(name, newImage string) error { + cfg, err := loadConfig(name) + if err != nil && os.IsNotExist(err) { + return nil + } + if err != nil { + return err + } + cfg.Image = newImage + cfg.ImagePath = "" + return storeConfig(name, cfg) +} + +func loadConfig(name string) (*proxyConfig, error) { + configFile := filepath.Join(proxydir, name+".json") + data, err := ioutil.ReadFile(configFile) + if err != nil { + return nil, err + } + var cfg proxyConfig + err = json.Unmarshal(data, &cfg) + if err != nil { + return nil, err + } + return &cfg, nil +} + +// storeConfig will write out the config only if it already exists +func storeConfig(name string, cfg *proxyConfig) error { + configFile := filepath.Join(proxydir, name+".json") + fd, err := os.OpenFile(configFile, os.O_RDWR, 0644) + if err != nil && os.IsNotExist(err) { + return nil + } + if err != nil { + return err + } + err = fd.Truncate(0) + if err != nil { + return err + } + enc := json.NewEncoder(fd) + return enc.Encode(cfg) +} diff --git a/internal/pkg/containerized/proxy_test.go b/internal/pkg/containerized/proxy_test.go new file mode 100644 index 0000000000..b98636e377 --- /dev/null +++ b/internal/pkg/containerized/proxy_test.go @@ -0,0 +1,68 @@ +package containerized + +import ( + "encoding/json" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "gotest.tools/assert" +) + +func TestUpdateConfigNotExist(t *testing.T) { + tmpdir, err := ioutil.TempDir("", "cfg-update") + assert.NilError(t, err) + defer os.RemoveAll(tmpdir) + origProxyDir := proxydir + defer func() { + proxydir = origProxyDir + }() + proxydir = tmpdir + name := "myname" + newImage := "newimage:foo" + err = updateConfig(name, newImage) + assert.NilError(t, err) +} + +func TestUpdateConfigBadJson(t *testing.T) { + tmpdir, err := ioutil.TempDir("", "cfg-update") + assert.NilError(t, err) + defer os.RemoveAll(tmpdir) + origProxyDir := proxydir + defer func() { + proxydir = origProxyDir + }() + proxydir = tmpdir + filename := filepath.Join(tmpdir, "dockerd.json") + err = ioutil.WriteFile(filename, []byte("not json"), 0644) + assert.NilError(t, err) + name := "dockerd" + newImage := "newimage:foo" + err = updateConfig(name, newImage) + assert.ErrorContains(t, err, "invalid character") +} + +func TestUpdateConfigHappyPath(t *testing.T) { + tmpdir, err := ioutil.TempDir("", "cfg-update") + assert.NilError(t, err) + defer os.RemoveAll(tmpdir) + origProxyDir := proxydir + defer func() { + proxydir = origProxyDir + }() + proxydir = tmpdir + filename := filepath.Join(tmpdir, "dockerd.json") + err = ioutil.WriteFile(filename, []byte("{}"), 0644) + assert.NilError(t, err) + name := "dockerd" + newImage := "newimage:foo" + err = updateConfig(name, newImage) + assert.NilError(t, err) + data, err := ioutil.ReadFile(filename) + assert.NilError(t, err) + var cfg map[string]string + err = json.Unmarshal(data, &cfg) + assert.NilError(t, err) + assert.Assert(t, cfg["image"] == newImage) +} diff --git a/internal/pkg/containerized/snapshot.go b/internal/pkg/containerized/snapshot.go index 62fcca3ac2..df13b348d7 100644 --- a/internal/pkg/containerized/snapshot.go +++ b/internal/pkg/containerized/snapshot.go @@ -50,6 +50,10 @@ func WithUpgrade(i containerd.Image) containerd.UpdateContainerOpts { return err } c.Image = i.Name() + err = updateConfig(c.ID, c.Image) + if err != nil { + return err + } c.SnapshotKey = revision.Key return nil } @@ -74,6 +78,10 @@ func WithRollback(ctx context.Context, client *containerd.Client, c *containers. return fmt.Errorf("snapshot %s has an empty service image label", prev.Key) } c.Image = snapshotImage + err = updateConfig(c.ID, c.Image) + if err != nil { + return err + } c.SnapshotKey = prev.Key return nil }