Skip to content

Commit 16cb26c

Browse files
committed
LVP support for local volumes in Windows
1 parent 448e0a0 commit 16cb26c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+7689
-194
lines changed

cmd/local-volume-provisioner/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ func main() {
8787

8888
klog.Info("Starting controller\n")
8989
procTable := deleter.NewProcTable()
90+
9091
go controller.StartLocalController(client, procTable, discoveryPeriod, &common.UserConfig{
9192
Node: node,
9293
DiscoveryMap: provisionerConfig.StorageClassConfig,

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.16
55
require (
66
github.com/ghodss/yaml v1.0.0
77
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
8+
github.com/kubernetes-csi/csi-proxy/client v1.0.1
89
github.com/onsi/ginkgo v1.14.0
910
github.com/onsi/gomega v1.10.1
1011
github.com/prometheus/client_golang v1.11.0

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5
4747
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
4848
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
4949
github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
50+
github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
51+
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
5052
github.com/Microsoft/hcsshim v0.8.10-0.20200715222032-5eafd1556990/go.mod h1:ay/0dTb7NsG8QMDfsRfLHgZo/6xAJShLe1+ePPflihk=
5153
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
5254
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
@@ -357,6 +359,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
357359
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
358360
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
359361
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
362+
github.com/kubernetes-csi/csi-proxy/client v1.0.1 h1:BPK9e5Fy0GcDRjDc9hqu7TnouSRujG6IvbH+PXSDOsY=
363+
github.com/kubernetes-csi/csi-proxy/client v1.0.1/go.mod h1:URLOkEbRhOwKVvGvug6HSKRTpLSFuQ/Gt3xahDag8qc=
360364
github.com/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc=
361365
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
362366
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=

pkg/common/common.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"os"
2424
"path"
2525
"path/filepath"
26+
"runtime"
2627
"strings"
2728

2829
"github.com/ghodss/yaml"
@@ -328,6 +329,8 @@ func ConfigMapDataToVolumeConfig(data map[string]string, provisionerConfig *Prov
328329
if config.MountDir == "" || config.HostDir == "" {
329330
return fmt.Errorf("Storage Class %v is misconfigured, missing HostDir or MountDir parameter", class)
330331
}
332+
config.MountDir = normalizePath(config.MountDir)
333+
config.HostDir = normalizePath(config.HostDir)
331334

332335
if config.VolumeMode == "" {
333336
config.VolumeMode = DefaultVolumeMode
@@ -354,6 +357,20 @@ func ConfigMapDataToVolumeConfig(data map[string]string, provisionerConfig *Prov
354357
return nil
355358
}
356359

360+
// normalizePath makes sure the given path is a valid path on Windows too
361+
// by making sure all instances of `/` are replaced with `\\`, and the
362+
// path beings with `c:`
363+
func normalizePath(path string) string {
364+
if runtime.GOOS != "windows" {
365+
return path
366+
}
367+
normalizedPath := strings.Replace(path, "/", "\\", -1)
368+
if strings.HasPrefix(normalizedPath, "\\") {
369+
normalizedPath = "c:" + normalizedPath
370+
}
371+
return normalizedPath
372+
}
373+
357374
func insertSpaces(original string) string {
358375
spaced := ""
359376
for _, line := range strings.Split(original, "\n") {
@@ -425,6 +442,11 @@ func GenerateMountName(mount *MountConfig) string {
425442

426443
// GetVolumeMode check volume mode of given path.
427444
func GetVolumeMode(volUtil util.VolumeUtil, fullPath string) (v1.PersistentVolumeMode, error) {
445+
if runtime.GOOS == "windows" {
446+
// only filesystem is supported in Windows
447+
return v1.PersistentVolumeFilesystem, nil
448+
}
449+
428450
isdir, errdir := volUtil.IsDir(fullPath)
429451
if isdir {
430452
return v1.PersistentVolumeFilesystem, nil

pkg/controller/controller.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import (
4343
)
4444

4545
// StartLocalController starts the sync loop for the local PV discovery and deleter
46-
func StartLocalController(client *kubernetes.Clientset, ptable deleter.ProcTable, discoveryPeriod time.Duration, config *common.UserConfig) {
46+
func StartLocalController(client *kubernetes.Clientset, ptable deleter.ProcTable, discoveryPeriod time.Duration, config *common.UserConfig) error {
4747
klog.Info("Initializing volume cache\n")
4848

4949
var provisionerName string
@@ -62,10 +62,16 @@ func StartLocalController(client *kubernetes.Clientset, ptable deleter.ProcTable
6262
// at same time don't list the apiserver simultaneously.
6363
resyncPeriod := time.Duration(config.MinResyncPeriod.Seconds()*(1+rand.Float64())) * time.Second
6464

65+
var err error
66+
volumeUtil, err := util.NewVolumeUtil()
67+
if err != nil {
68+
klog.Fatalf("Error initializing VolumeUtil: %v", err)
69+
}
70+
6571
runtimeConfig := &common.RuntimeConfig{
6672
UserConfig: config,
6773
Cache: cache.NewVolumeCache(),
68-
VolUtil: util.NewVolumeUtil(),
74+
VolUtil: volumeUtil,
6975
APIUtil: util.NewAPIUtil(client),
7076
Client: client,
7177
Name: provisionerName,
@@ -77,7 +83,6 @@ func StartLocalController(client *kubernetes.Clientset, ptable deleter.ProcTable
7783
populator.NewPopulator(runtimeConfig)
7884

7985
var jobController deleter.JobController
80-
var err error
8186
if runtimeConfig.UseJobForCleaning {
8287
labels := map[string]string{common.NodeNameLabel: config.Node.Name}
8388
jobController, err = deleter.NewJobController(labels, runtimeConfig)
@@ -114,4 +119,7 @@ func StartLocalController(client *kubernetes.Clientset, ptable deleter.ProcTable
114119
discoverer.DiscoverLocalVolumes()
115120
time.Sleep(discoveryPeriod)
116121
}
122+
123+
// unreachable
124+
return nil
117125
}

pkg/discovery/discovery.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"hash/fnv"
2424
"net/http"
2525
"path/filepath"
26+
"runtime"
2627
"strings"
2728
"sync"
2829
"time"
@@ -266,6 +267,7 @@ func (d *Discoverer) discoverVolumesAtPath(class string, config common.MountConf
266267

267268
// Retrieve list of mount points to iterate through discovered paths (aka files) below
268269
mountPoints, err := d.RuntimeConfig.Mounter.List()
270+
klog.V(4).Infof("[DEBUG] the mount points are %v", mountPoints)
269271
if err != nil {
270272
return fmt.Errorf("error retrieving mountpoints: %v", err)
271273
}
@@ -360,10 +362,13 @@ func (d *Discoverer) discoverVolumesAtPath(class string, config common.MountConf
360362
discoErrors = append(discoErrors, fmt.Errorf("path %q of filesystem mode cannot be used to create block volume", filePath))
361363
continue
362364
}
363-
// Validate that this path is an actual mountpoint
364-
if _, isMntPnt := mountPointMap[filePath]; isMntPnt == false {
365-
discoErrors = append(discoErrors, fmt.Errorf("path %q is not an actual mountpoint", filePath))
366-
continue
365+
// TODO(mauriciopoppe): skipping the mountpoint verification in Windows, unlike Linux there's no /proc/mounts file to check
366+
if runtime.GOOS != "windows" {
367+
// Validate that this path is an actual mountpoint
368+
if _, isMntPnt := mountPointMap[filePath]; isMntPnt == false {
369+
discoErrors = append(discoErrors, fmt.Errorf("path %q is not an actual mountpoint", filePath))
370+
continue
371+
}
367372
}
368373
capacityByte, err = d.VolUtil.GetFsCapacityByte(filePath)
369374
if err != nil {

pkg/util/csi_proxy_v1_windows.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//go:build windows
2+
// +build windows
3+
4+
/*
5+
Copyright 2021 The Kubernetes Authors.
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package util
18+
19+
import (
20+
"context"
21+
"fmt"
22+
23+
volumeapi "github.com/kubernetes-csi/csi-proxy/client/api/volume/v1"
24+
volumeclient "github.com/kubernetes-csi/csi-proxy/client/groups/volume/v1"
25+
)
26+
27+
// CSIProxyV1 is the CSI Proxy implementation that uses the v1 API
28+
type CSIProxyV1 struct {
29+
VolumeClient *volumeclient.Client
30+
}
31+
32+
// check that CSIProxyV1 implements CSIProxy
33+
var _ CSIProxy = &CSIProxyV1{}
34+
35+
func NewCSIProxyV1() (*CSIProxyV1, error) {
36+
volumeClient, err := volumeclient.NewClient()
37+
if err != nil {
38+
return nil, err
39+
}
40+
return &CSIProxyV1{
41+
VolumeClient: volumeClient,
42+
}, nil
43+
}
44+
45+
// GetAPIVersions returns the versions of the client APIs.
46+
func (proxy *CSIProxyV1) GetAPIVersions() string {
47+
return fmt.Sprintf(
48+
"API Versions Volume: %s",
49+
volumeclient.Version,
50+
)
51+
}
52+
53+
// GetVolumeId returns the volumeId of the volume mounted at `mountPath`
54+
func (proxy *CSIProxyV1) GetVolumeId(mountPath string) (volumeId string, err error) {
55+
getVolumeIdFromTargetPathResponse, err := proxy.VolumeClient.GetVolumeIDFromTargetPath(
56+
context.Background(),
57+
&volumeapi.GetVolumeIDFromTargetPathRequest{
58+
TargetPath: mountPath,
59+
},
60+
)
61+
if err != nil {
62+
return "", err
63+
}
64+
return getVolumeIdFromTargetPathResponse.VolumeId, nil
65+
}
66+
67+
// GetVolumeStats gets the volume stats of a volume identified by `volumeId`
68+
func (proxy *CSIProxyV1) GetVolumeStats(volumeId string) (totalBytes int64, usedBytes int64, err error) {
69+
getVolumeStatsResponse, err := proxy.VolumeClient.GetVolumeStats(
70+
context.Background(),
71+
&volumeapi.GetVolumeStatsRequest{
72+
VolumeId: volumeId,
73+
},
74+
)
75+
if err != nil {
76+
return 0, 0, err
77+
}
78+
return getVolumeStatsResponse.TotalBytes, getVolumeStatsResponse.UsedBytes, nil
79+
}
80+
81+
// FormatVolume formats a volume identified by `volumeId`
82+
func (proxy *CSIProxyV1) FormatVolume(volumeId string) (err error) {
83+
_, err = proxy.VolumeClient.FormatVolume(
84+
context.Background(),
85+
&volumeapi.FormatVolumeRequest{
86+
VolumeId: volumeId,
87+
},
88+
)
89+
if err != nil {
90+
return err
91+
}
92+
return nil
93+
}

pkg/util/csi_proxy_v1beta_windows.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//go:build windows
2+
// +build windows
3+
4+
/*
5+
Copyright 2021 The Kubernetes Authors.
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package util
18+
19+
import (
20+
"context"
21+
"fmt"
22+
23+
volumeapi "github.com/kubernetes-csi/csi-proxy/client/api/volume/v1beta2"
24+
volumeclient "github.com/kubernetes-csi/csi-proxy/client/groups/volume/v1beta2"
25+
)
26+
27+
// CSIProxyV1Beta is the CSI Proxy implementation that uses the v1 API
28+
type CSIProxyV1Beta struct {
29+
VolumeClient *volumeclient.Client
30+
}
31+
32+
// check that CSIProxyV1Beta implements CSIProxy
33+
var _ CSIProxy = &CSIProxyV1Beta{}
34+
35+
func NewCSIProxyV1Beta() (*CSIProxyV1Beta, error) {
36+
volumeClient, err := volumeclient.NewClient()
37+
if err != nil {
38+
return nil, err
39+
}
40+
return &CSIProxyV1Beta{
41+
VolumeClient: volumeClient,
42+
}, nil
43+
}
44+
45+
// GetAPIVersions returns the versions of the client APIs.
46+
func (proxy *CSIProxyV1Beta) GetAPIVersions() string {
47+
return fmt.Sprintf(
48+
"API Versions Volume: %s",
49+
volumeclient.Version,
50+
)
51+
}
52+
53+
// GetVolumeId returns the volumeId of the volume mounted at `mountPath`
54+
func (proxy *CSIProxyV1Beta) GetVolumeId(mountPath string) (volumeId string, err error) {
55+
getVolumeIdFromTargetPathResponse, err := proxy.VolumeClient.GetVolumeIDFromMount(
56+
context.Background(),
57+
&volumeapi.VolumeIDFromMountRequest{
58+
Mount: mountPath,
59+
},
60+
)
61+
if err != nil {
62+
return "", err
63+
}
64+
return getVolumeIdFromTargetPathResponse.VolumeId, nil
65+
}
66+
67+
// GetVolumeStats gets the volume information
68+
func (proxy *CSIProxyV1Beta) GetVolumeStats(volumeId string) (totalBytes int64, usedBytes int64, err error) {
69+
getVolumeStatsResponse, err := proxy.VolumeClient.VolumeStats(
70+
context.Background(),
71+
&volumeapi.VolumeStatsRequest{
72+
VolumeId: volumeId,
73+
},
74+
)
75+
if err != nil {
76+
return 0, 0, err
77+
}
78+
return getVolumeStatsResponse.VolumeSize, getVolumeStatsResponse.VolumeUsedSize, nil
79+
}
80+
81+
// FormatVolume formats a volume identified by `volumeId`
82+
func (proxy *CSIProxyV1Beta) FormatVolume(volumeId string) (err error) {
83+
_, err = proxy.VolumeClient.FormatVolume(
84+
context.Background(),
85+
&volumeapi.FormatVolumeRequest{
86+
VolumeId: volumeId,
87+
},
88+
)
89+
if err != nil {
90+
return err
91+
}
92+
return nil
93+
}

0 commit comments

Comments
 (0)