Skip to content

Commit

Permalink
Merge pull request #6275 from gabriel-samfira/enable-volume-ownership…
Browse files Browse the repository at this point in the history
…-test

Integration: Enable TestVolumeOwnership on Windows
  • Loading branch information
dmcgowan committed Dec 14, 2021
2 parents d0da25c + 77a321a commit 0def0db
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 18 deletions.
86 changes: 68 additions & 18 deletions integration/volume_copy_up_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,22 @@ package integration

import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
goruntime "runtime"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
exec "golang.org/x/sys/execabs"
)

const (
containerUserName = "ContainerUser"
// containerUserSID is a well known SID that is set on the
// ContainerUser username inside a Windows container.
containerUserSID = "S-1-5-93-2-2"
)

func TestVolumeCopyUp(t *testing.T) {
Expand Down Expand Up @@ -62,12 +71,14 @@ func TestVolumeCopyUp(t *testing.T) {
assert.Equal(t, "test_content\n", string(stdout))

t.Logf("Check host path of the volume")
// Windows paths might have spaces in them (e.g.: Program Files), which would
// cause issues for this command. This will allow us to bypass them.
hostCmd := fmt.Sprintf("find '%s/containers/%s/volumes/' -type f -print0 | xargs -0 cat", *criRoot, cn)
output, err := exec.Command("sh", "-c", hostCmd).CombinedOutput()
volumePaths, err := getHostPathForVolumes(*criRoot, cn)
require.NoError(t, err)
assert.Equal(t, len(volumePaths), 1, "expected exactly 1 volume")

testFilePath := filepath.Join(volumePaths[0], "test_file")
contents, err := ioutil.ReadFile(testFilePath)
require.NoError(t, err)
assert.Equal(t, "test_content\n", string(output))
assert.Equal(t, "test_content\n", string(contents))

t.Logf("Update volume from inside the container")
_, _, err = runtimeService.ExecSync(cn, []string{
Expand All @@ -78,15 +89,12 @@ func TestVolumeCopyUp(t *testing.T) {
require.NoError(t, err)

t.Logf("Check whether host path of the volume is updated")
output, err = exec.Command("sh", "-c", hostCmd).CombinedOutput()
contents, err = ioutil.ReadFile(testFilePath)
require.NoError(t, err)
assert.Equal(t, "new_content\n", string(output))
assert.Equal(t, "new_content\n", string(contents))
}

func TestVolumeOwnership(t *testing.T) {
if goruntime.GOOS == "windows" {
t.Skip("Skipped on Windows.")
}
var (
testImage = GetImage(VolumeOwnership)
execTimeout = time.Minute
Expand All @@ -101,7 +109,7 @@ func TestVolumeOwnership(t *testing.T) {
cnConfig := ContainerConfig(
"container",
testImage,
WithCommand("tail", "-f", "/dev/null"),
WithCommand("sleep", "150"),
)
cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig)
require.NoError(t, err)
Expand All @@ -111,17 +119,59 @@ func TestVolumeOwnership(t *testing.T) {

// ghcr.io/containerd/volume-ownership:2.1 contains a test_dir
// volume, which is owned by nobody:nogroup.
// On Windows, the folder is situated in C:\volumes\test_dir and is owned
// by ContainerUser (SID: S-1-5-93-2-2). A helper tool get_owner.exe should
// exist inside the container that returns the owner in the form of USERNAME:SID.
t.Logf("Check ownership of test directory inside container")
stdout, stderr, err := runtimeService.ExecSync(cn, []string{

cmd := []string{
"stat", "-c", "%U:%G", "/test_dir",
}, execTimeout)
}
expectedContainerOutput := "nobody:nogroup\n"
expectedHostOutput := "nobody:nogroup\n"
if goruntime.GOOS == "windows" {
cmd = []string{
"C:\\bin\\get_owner.exe",
"C:\\volumes\\test_dir",
}
expectedContainerOutput = fmt.Sprintf("%s:%s", containerUserName, containerUserSID)
// The username is unknown on the host, but we can still get the SID.
expectedHostOutput = containerUserSID
}
stdout, stderr, err := runtimeService.ExecSync(cn, cmd, execTimeout)
require.NoError(t, err)
assert.Empty(t, stderr)
assert.Equal(t, "nobody:nogroup\n", string(stdout))
assert.Equal(t, expectedContainerOutput, string(stdout))

t.Logf("Check ownership of test directory on the host")
hostCmd := fmt.Sprintf("find %s/containers/%s/volumes/* | xargs stat -c %%U:%%G", *criRoot, cn)
output, err := exec.Command("sh", "-c", hostCmd).CombinedOutput()
volumePaths, err := getHostPathForVolumes(*criRoot, cn)
require.NoError(t, err)
assert.Equal(t, "nobody:nogroup\n", string(output))
assert.Equal(t, len(volumePaths), 1, "expected exactly 1 volume")

output, err := getOwnership(volumePaths[0])
require.NoError(t, err)
assert.Equal(t, expectedHostOutput, output)
}

func getHostPathForVolumes(criRoot, containerID string) ([]string, error) {
hostPath := filepath.Join(criRoot, "containers", containerID, "volumes")
if _, err := os.Stat(hostPath); err != nil {
return nil, err
}

volumes, err := ioutil.ReadDir(hostPath)
if err != nil {
return nil, err
}

if len(volumes) == 0 {
return []string{}, nil
}

volumePaths := make([]string, len(volumes))
for idx, volume := range volumes {
volumePaths[idx] = filepath.Join(hostPath, volume.Name())
}

return volumePaths, nil
}
35 changes: 35 additions & 0 deletions integration/volume_copy_up_unix_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//go:build !windows
// +build !windows

/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package integration

import (
"fmt"

exec "golang.org/x/sys/execabs"
)

func getOwnership(path string) (string, error) {
hostCmd := fmt.Sprintf("stat -c %%U:%%G '%s'", path)
output, err := exec.Command("sh", "-c", hostCmd).CombinedOutput()
if err != nil {
return "", err
}
return string(output), nil
}
40 changes: 40 additions & 0 deletions integration/volume_copy_up_windows_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//go:build windows
// +build windows

/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package integration

import (
"golang.org/x/sys/windows"
)

func getOwnership(path string) (string, error) {
secInfo, err := windows.GetNamedSecurityInfo(
path, windows.SE_FILE_OBJECT,
windows.OWNER_SECURITY_INFORMATION|windows.DACL_SECURITY_INFORMATION)

if err != nil {
return "", err
}

sid, _, err := secInfo.Owner()
if err != nil {
return "", err
}
return sid.String(), nil
}

0 comments on commit 0def0db

Please sign in to comment.