forked from LaconicNetwork/kompose
Add support for windows volume (#1417)
Signed-off-by: aiyijing <aiyijing@live.com>
This commit is contained in:
@@ -64,6 +64,13 @@ func CreateOutFile(out string) (*os.File, error) {
|
||||
|
||||
// ParseVolume parses a given volume, which might be [name:][host:]container[:access_mode]
|
||||
func ParseVolume(volume string) (name, host, container, mode string, err error) {
|
||||
if containWindowsPath(volume) {
|
||||
return parseWindowsVolume(volume)
|
||||
}
|
||||
return parseVolume(volume)
|
||||
}
|
||||
|
||||
func parseVolume(volume string) (name, host, container, mode string, err error) {
|
||||
separator := ":"
|
||||
|
||||
// Parse based on ":"
|
||||
@@ -112,6 +119,88 @@ func ParseVolume(volume string) (name, host, container, mode string, err error)
|
||||
return
|
||||
}
|
||||
|
||||
// parseVolume parses window volume.
|
||||
// example: windows host mount to windows container
|
||||
// volume = dataVolumeName:C:\Users\Data:D:\config:rw
|
||||
// it can be parsed:
|
||||
// name=dataVolumeName, host=C:\Users\Data, container=D:\config, mode=rw
|
||||
// example: windows host mount to linux container
|
||||
// volume = dataVolumeName:C:\Users\Data:/etc/config:rw
|
||||
// it can be parsed:
|
||||
// name=dataVolumeName, host=C:\Users\Data, container=/etc/config, mode=rw
|
||||
func parseWindowsVolume(volume string) (name, host, container, mode string, err error) {
|
||||
var (
|
||||
buffer, volumePaths []string
|
||||
volumeStrings = strings.Split(volume, ":")
|
||||
)
|
||||
|
||||
// extract path and leave order
|
||||
for _, fragment := range volumeStrings {
|
||||
switch {
|
||||
case containWindowsPath(fragment):
|
||||
if len(buffer) == 0 {
|
||||
err = fmt.Errorf("invalid windows volume %s", volume)
|
||||
return
|
||||
}
|
||||
|
||||
driveLetter := buffer[len(buffer)-1]
|
||||
if len(driveLetter) != 1 {
|
||||
err = fmt.Errorf("invalid windows volume %s", volume)
|
||||
return
|
||||
}
|
||||
volumePaths = append(volumePaths, driveLetter+":"+fragment)
|
||||
buffer = buffer[:len(buffer)-1]
|
||||
|
||||
case isPath(fragment):
|
||||
volumePaths = append(volumePaths, fragment)
|
||||
default:
|
||||
buffer = append(buffer, fragment)
|
||||
}
|
||||
}
|
||||
|
||||
// set name and mode if exist
|
||||
if len(buffer) == 1 {
|
||||
if volumeStrings[0] == buffer[0] {
|
||||
name = buffer[0]
|
||||
} else if volumeStrings[len(volumeStrings)-1] == buffer[0] {
|
||||
mode = buffer[0]
|
||||
}
|
||||
} else if len(buffer) == 2 {
|
||||
name = buffer[0]
|
||||
mode = buffer[1]
|
||||
} else if len(buffer) > 2 {
|
||||
err = fmt.Errorf("invalid windows volume %s", volume)
|
||||
return
|
||||
}
|
||||
|
||||
// Support in pass time
|
||||
// Check to see if :Z or :z exists. We do not support SELinux relabeling at the moment.
|
||||
// See https://github.com/kubernetes/kompose/issues/176
|
||||
// Otherwise, check to see if "rw" or "ro" has been passed
|
||||
if mode == "z" || mode == "Z" {
|
||||
log.Warnf("Volume mount \"%s\" will be mounted without labeling support. :z or :Z not supported", volume)
|
||||
mode = ""
|
||||
}
|
||||
|
||||
// Set host and container if exist
|
||||
if len(volumePaths) == 1 {
|
||||
container = volumePaths[0]
|
||||
} else if len(volumePaths) == 2 {
|
||||
host = volumePaths[0]
|
||||
container = volumePaths[1]
|
||||
} else {
|
||||
err = fmt.Errorf("invalid windows volume %s", volume)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// containWindowsPath check whether it contains windows path.
|
||||
// windows path's separator is "\"
|
||||
func containWindowsPath(substring string) bool {
|
||||
return strings.Contains(substring, "\\")
|
||||
}
|
||||
|
||||
// ParseIngressPath parse path for ingress.
|
||||
// eg. example.com/org -> example.com org
|
||||
func ParseIngressPath(url string) (string, string) {
|
||||
|
||||
@@ -34,6 +34,7 @@ func TestFormatProviderName(t *testing.T) {
|
||||
// When passing "z" or "Z" we expect "" back.
|
||||
func TestZParseVolumeLabeling(t *testing.T) {
|
||||
testCase := "/foobar:/foobar:Z"
|
||||
windowVolumeTestCase := "C:\\foobar:/foobar:Z"
|
||||
_, _, _, mode, err := ParseVolume(testCase)
|
||||
if err != nil {
|
||||
t.Errorf("In test case %q, returned unexpected error %v", testCase, err)
|
||||
@@ -41,6 +42,204 @@ func TestZParseVolumeLabeling(t *testing.T) {
|
||||
if mode != "" {
|
||||
t.Errorf("In test case %q, returned mode %s, expected \"\"", testCase, mode)
|
||||
}
|
||||
|
||||
_, _, _, mode, err = ParseVolume(windowVolumeTestCase)
|
||||
if err != nil {
|
||||
t.Errorf("In test case %q, returned unexpected error %v", windowVolumeTestCase, err)
|
||||
}
|
||||
if mode != "" {
|
||||
t.Errorf("In test case %q, returned mode %s, expected \"\"", windowVolumeTestCase, mode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseWindowsVolumeMountLinuxContainer(t *testing.T) {
|
||||
name := "datavolume"
|
||||
windowsHosts := "C:\\Users"
|
||||
linuxContainer := "/etc/configs/"
|
||||
mode := "rw"
|
||||
|
||||
tests := []struct {
|
||||
test, volume, name, host, container, mode string
|
||||
}{
|
||||
{
|
||||
"name:host:container:mode",
|
||||
fmt.Sprintf("%s:%s:%s:%s", name, windowsHosts, linuxContainer, mode),
|
||||
name,
|
||||
windowsHosts,
|
||||
linuxContainer,
|
||||
mode,
|
||||
},
|
||||
{
|
||||
"host:container:mode",
|
||||
fmt.Sprintf("%s:%s:%s", windowsHosts, linuxContainer, mode),
|
||||
"",
|
||||
windowsHosts,
|
||||
linuxContainer,
|
||||
mode,
|
||||
},
|
||||
{
|
||||
"name:container:mode",
|
||||
fmt.Sprintf("%s:%s:%s", name, linuxContainer, mode),
|
||||
name,
|
||||
"",
|
||||
linuxContainer,
|
||||
mode,
|
||||
},
|
||||
{
|
||||
"name:host:container",
|
||||
fmt.Sprintf("%s:%s:%s", name, windowsHosts, linuxContainer),
|
||||
name,
|
||||
windowsHosts,
|
||||
linuxContainer,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"host:container",
|
||||
fmt.Sprintf("%s:%s", windowsHosts, linuxContainer),
|
||||
"",
|
||||
windowsHosts,
|
||||
linuxContainer,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"container:mode",
|
||||
fmt.Sprintf("%s:%s", linuxContainer, mode),
|
||||
"",
|
||||
"",
|
||||
linuxContainer,
|
||||
mode,
|
||||
},
|
||||
{
|
||||
"name:container",
|
||||
fmt.Sprintf("%s:%s", name, linuxContainer),
|
||||
name,
|
||||
"",
|
||||
linuxContainer,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"container",
|
||||
fmt.Sprintf("%s", linuxContainer),
|
||||
"",
|
||||
"",
|
||||
linuxContainer,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
name, host, container, mode, err := ParseVolume(test.volume)
|
||||
if err != nil {
|
||||
t.Errorf("In test case %q, returned unexpected error %v", test.test, err)
|
||||
}
|
||||
if name != test.name {
|
||||
t.Errorf("In test case %q, returned volume name %s, expected %s", test.test, name, test.name)
|
||||
}
|
||||
if host != test.host {
|
||||
t.Errorf("In test case %q, returned host path %s, expected %s", test.test, host, test.host)
|
||||
}
|
||||
if container != test.container {
|
||||
t.Errorf("In test case %q, returned container path %s, expected %s", test.test, container, test.container)
|
||||
}
|
||||
if mode != test.mode {
|
||||
t.Errorf("In test case %q, returned access mode %s, expected %s", test.test, mode, test.mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseWindowsVolumeMountWindowsContainer(t *testing.T) {
|
||||
name := "datavolume"
|
||||
windowsHosts := "C:\\Users"
|
||||
windowsContainer := "D:\\Users"
|
||||
mode := "rw"
|
||||
|
||||
tests := []struct {
|
||||
test, volume, name, host, container, mode string
|
||||
}{
|
||||
{
|
||||
"name:host:container:mode",
|
||||
fmt.Sprintf("%s:%s:%s:%s", name, windowsHosts, windowsContainer, mode),
|
||||
name,
|
||||
windowsHosts,
|
||||
windowsContainer,
|
||||
mode,
|
||||
},
|
||||
{
|
||||
"host:container:mode",
|
||||
fmt.Sprintf("%s:%s:%s", windowsHosts, windowsContainer, mode),
|
||||
"",
|
||||
windowsHosts,
|
||||
windowsContainer,
|
||||
mode,
|
||||
},
|
||||
{
|
||||
"name:container:mode",
|
||||
fmt.Sprintf("%s:%s:%s", name, windowsContainer, mode),
|
||||
name,
|
||||
"",
|
||||
windowsContainer,
|
||||
mode,
|
||||
},
|
||||
{
|
||||
"name:host:container",
|
||||
fmt.Sprintf("%s:%s:%s", name, windowsHosts, windowsContainer),
|
||||
name,
|
||||
windowsHosts,
|
||||
windowsContainer,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"host:container",
|
||||
fmt.Sprintf("%s:%s", windowsHosts, windowsContainer),
|
||||
"",
|
||||
windowsHosts,
|
||||
windowsContainer,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"container:mode",
|
||||
fmt.Sprintf("%s:%s", windowsContainer, mode),
|
||||
"",
|
||||
"",
|
||||
windowsContainer,
|
||||
mode,
|
||||
},
|
||||
{
|
||||
"name:container",
|
||||
fmt.Sprintf("%s:%s", name, windowsContainer),
|
||||
name,
|
||||
"",
|
||||
windowsContainer,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"container",
|
||||
fmt.Sprintf("%s", windowsContainer),
|
||||
"",
|
||||
"",
|
||||
windowsContainer,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
name, host, container, mode, err := ParseVolume(test.volume)
|
||||
if err != nil {
|
||||
t.Errorf("In test case %q, returned unexpected error %v", test.test, err)
|
||||
}
|
||||
if name != test.name {
|
||||
t.Errorf("In test case %q, returned volume name %s, expected %s", test.test, name, test.name)
|
||||
}
|
||||
if host != test.host {
|
||||
t.Errorf("In test case %q, returned host path %s, expected %s", test.test, host, test.host)
|
||||
}
|
||||
if container != test.container {
|
||||
t.Errorf("In test case %q, returned container path %s, expected %s", test.test, container, test.container)
|
||||
}
|
||||
if mode != test.mode {
|
||||
t.Errorf("In test case %q, returned access mode %s, expected %s", test.test, mode, test.mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseVolume(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user