From 9a0434d6bf257523a32b8add93faa9f084c036e5 Mon Sep 17 00:00:00 2001 From: y00316549 Date: Fri, 1 Jun 2018 14:48:43 +0800 Subject: [PATCH] virtcontainers: make kataAgent/createContainer can decode old specs.Spec in old specs.Spec, Capabilities is [] string, but we don't use CompatOCISpec for compatibility in kataAgent/createContainer. fixes #333 Signed-off-by: y00316549 --- cli/main_test.go | 6 +- virtcontainers/pkg/oci/utils.go | 22 +++++- virtcontainers/pkg/oci/utils_test.go | 107 +++++++++++++++++++++++++-- 3 files changed, 123 insertions(+), 12 deletions(-) diff --git a/cli/main_test.go b/cli/main_test.go index 9cf36a52f8..9c111c94fb 100644 --- a/cli/main_test.go +++ b/cli/main_test.go @@ -421,7 +421,11 @@ func readOCIConfigFile(configPath string) (oci.CompatOCISpec, error) { if err := json.Unmarshal(data, &ociSpec); err != nil { return oci.CompatOCISpec{}, err } - + caps, err := oci.ContainerCapabilities(ociSpec) + if err != nil { + return oci.CompatOCISpec{}, err + } + ociSpec.Process.Capabilities = caps return ociSpec, nil } diff --git a/virtcontainers/pkg/oci/utils.go b/virtcontainers/pkg/oci/utils.go index c886befbda..dacce20587 100644 --- a/virtcontainers/pkg/oci/utils.go +++ b/virtcontainers/pkg/oci/utils.go @@ -320,6 +320,14 @@ func containerCapabilities(s CompatOCISpec) (vc.LinuxCapabilities, error) { return c, nil } +// ContainerCapabilities return a LinuxCapabilities for virtcontainer +func ContainerCapabilities(s CompatOCISpec) (vc.LinuxCapabilities, error) { + if s.Process == nil { + return vc.LinuxCapabilities{}, fmt.Errorf("ContainerCapabilities, Process is nil") + } + return containerCapabilities(s) +} + func networkConfig(ocispec CompatOCISpec, config RuntimeConfig) (vc.NetworkConfig, error) { linux := ocispec.Linux if linux == nil { @@ -365,6 +373,11 @@ func ParseConfigJSON(bundlePath string) (CompatOCISpec, error) { if err := json.Unmarshal(configByte, &ocispec); err != nil { return CompatOCISpec{}, err } + caps, err := ContainerCapabilities(ocispec) + if err != nil { + return CompatOCISpec{}, err + } + ocispec.Process.Capabilities = caps return ocispec, nil } @@ -554,9 +567,12 @@ func ContainerConfig(ocispec CompatOCISpec, bundlePath, cid, console string, det return vc.ContainerConfig{}, err } - cmd.Capabilities, err = containerCapabilities(ocispec) - if err != nil { - return vc.ContainerConfig{}, err + if ocispec.Process != nil { + caps, ok := ocispec.Process.Capabilities.(vc.LinuxCapabilities) + if !ok { + return vc.ContainerConfig{}, fmt.Errorf("Unexpected format for capabilities: %v", ocispec.Process.Capabilities) + } + cmd.Capabilities = caps } var resources vc.ContainerResources diff --git a/virtcontainers/pkg/oci/utils_test.go b/virtcontainers/pkg/oci/utils_test.go index 37385ff2f4..5d1f7c746c 100644 --- a/virtcontainers/pkg/oci/utils_test.go +++ b/virtcontainers/pkg/oci/utils_test.go @@ -24,11 +24,54 @@ import ( vcAnnotations "github.com/kata-containers/runtime/virtcontainers/pkg/annotations" ) -const tempBundlePath = "/tmp/virtc/ocibundle/" -const containerID = "virtc-oci-test" -const consolePath = "/tmp/virtc/console" -const fileMode = os.FileMode(0640) -const dirMode = os.FileMode(0750) +const ( + tempBundlePath = "/tmp/virtc/ocibundle/" + containerID = "virtc-oci-test" + consolePath = "/tmp/virtc/console" + fileMode = os.FileMode(0640) + dirMode = os.FileMode(0750) + + capabilitiesSpecArray = ` + { + "ociVersion": "1.0.0-rc2-dev", + "process": { + "capabilities": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID" + ] + } + }` + + capabilitiesSpecStruct = ` + { + "ociVersion": "1.0.0-rc5", + "process": { + "capabilities": { + "bounding": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID" + ], + "effective": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID" + ], + "inheritable": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID" + ], + "permitted": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID" + ] + } + } + }` +) func createConfig(fileName string, fileData string) (string, error) { configPath := path.Join(tempBundlePath, fileName) @@ -127,6 +170,13 @@ func TestMinimalSandboxConfig(t *testing.T) { if err := json.Unmarshal([]byte(minimalConfig), &minimalOCISpec); err != nil { t.Fatal(err) } + if minimalOCISpec.Process != nil { + caps, err := ContainerCapabilities(minimalOCISpec) + if err != nil { + t.Fatal(err) + } + minimalOCISpec.Process.Capabilities = caps + } ociSpecJSON, err := json.Marshal(minimalOCISpec) if err != nil { t.Fatal(err) @@ -714,7 +764,7 @@ func TestContainerCapabilities(t *testing.T) { "ambient": []interface{}{""}, } - c, err := containerCapabilities(ociSpec) + c, err := ContainerCapabilities(ociSpec) assert.Nil(t, err) assert.Equal(t, c.Bounding, []string{"CAP_KILL"}) assert.Equal(t, c.Effective, []string{"CAP_KILL", "CAP_LEASE"}) @@ -724,7 +774,7 @@ func TestContainerCapabilities(t *testing.T) { ociSpec.Process.Capabilities = []interface{}{"CAP_LEASE", "CAP_SETUID"} - c, err = containerCapabilities(ociSpec) + c, err = ContainerCapabilities(ociSpec) assert.Nil(t, err) assert.Equal(t, c.Bounding, []string{"CAP_LEASE", "CAP_SETUID"}) assert.Equal(t, c.Effective, []string{"CAP_LEASE", "CAP_SETUID"}) @@ -734,7 +784,7 @@ func TestContainerCapabilities(t *testing.T) { ociSpec.Process.Capabilities = nil - c, err = containerCapabilities(ociSpec) + c, err = ContainerCapabilities(ociSpec) assert.Nil(t, err) assert.Equal(t, c.Bounding, []string(nil)) assert.Equal(t, c.Effective, []string(nil)) @@ -743,6 +793,47 @@ func TestContainerCapabilities(t *testing.T) { assert.Equal(t, c.Ambient, []string(nil)) } +// use specs.Spec to decode the spec, the content of capabilities is [] string +func TestCompatOCISpecWithArray(t *testing.T) { + compatOCISpec := CompatOCISpec{} + err := json.Unmarshal([]byte(capabilitiesSpecArray), &compatOCISpec) + assert.Nil(t, err, "use CompatOCISpec to decode capabilitiesSpecArray failed") + + ociSpecJSON, err := json.Marshal(compatOCISpec) + assert.Nil(t, err, "encode compatOCISpec failed") + + // use specs.Spec to decode the spec, specs.Spec' capabilities is struct, + // but the content of spec' capabilities is [] string + ociSpec := specs.Spec{} + err = json.Unmarshal(ociSpecJSON, &ociSpec) + assert.NotNil(t, err, "This test should fail") + + caps, err := ContainerCapabilities(compatOCISpec) + assert.Nil(t, err, "decode capabilities failed") + compatOCISpec.Process.Capabilities = caps + + ociSpecJSON, err = json.Marshal(compatOCISpec) + assert.Nil(t, err, "encode compatOCISpec failed") + + // capabilities has been chaged to struct + err = json.Unmarshal(ociSpecJSON, &ociSpec) + assert.Nil(t, err, "This test should fail") +} + +// use specs.Spec to decode the spec, the content of capabilities is struct +func TestCompatOCISpecWithStruct(t *testing.T) { + compatOCISpec := CompatOCISpec{} + err := json.Unmarshal([]byte(capabilitiesSpecStruct), &compatOCISpec) + assert.Nil(t, err, "use CompatOCISpec to decode capabilitiesSpecStruct failed") + + ociSpecJSON, err := json.Marshal(compatOCISpec) + assert.Nil(t, err, "encode compatOCISpec failed") + + ociSpec := specs.Spec{} + err = json.Unmarshal(ociSpecJSON, &ociSpec) + assert.Nil(t, err, "This test should not fail") +} + func TestMain(m *testing.M) { /* Create temp bundle directory if necessary */ err := os.MkdirAll(tempBundlePath, dirMode)