@@ -17,12 +17,22 @@ limitations under the License.
17
17
package smb
18
18
19
19
import (
20
+ "context"
21
+ "errors"
20
22
"fmt"
23
+ "net"
24
+ "os"
25
+ "path/filepath"
21
26
"strings"
22
27
"time"
23
28
24
29
"github.com/container-storage-interface/spec/lib/go/csi"
25
30
31
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32
+ "k8s.io/client-go/kubernetes"
33
+ "k8s.io/client-go/rest"
34
+ "k8s.io/client-go/tools/clientcmd"
35
+ certutil "k8s.io/client-go/util/cert"
26
36
"k8s.io/klog/v2"
27
37
mount "k8s.io/mount-utils"
28
38
@@ -40,8 +50,12 @@ const (
40
50
subDirField = "subdir"
41
51
domainField = "domain"
42
52
mountOptionsField = "mountoptions"
53
+ secretNameField = "secretname"
54
+ secretNamespaceField = "secretnamespace"
43
55
paramOnDelete = "ondelete"
44
56
defaultDomainName = "AZURE"
57
+ ephemeralField = "csi.storage.k8s.io/ephemeral"
58
+ podNamespaceField = "csi.storage.k8s.io/pod.namespace"
45
59
pvcNameKey = "csi.storage.k8s.io/pvc/name"
46
60
pvcNamespaceKey = "csi.storage.k8s.io/pvc/namespace"
47
61
pvNameKey = "csi.storage.k8s.io/pv/name"
@@ -56,6 +70,7 @@ const (
56
70
dirMode = "dir_mode"
57
71
defaultFileMode = "0777"
58
72
defaultDirMode = "0777"
73
+ trueValue = "true"
59
74
)
60
75
61
76
var supportedOnDeleteValues = []string {"" , "delete" , retain , archive }
@@ -74,6 +89,7 @@ type DriverOptions struct {
74
89
DefaultOnDeletePolicy string
75
90
RemoveArchivedVolumePath bool
76
91
EnableWindowsHostProcess bool
92
+ Kubeconfig string
77
93
}
78
94
79
95
// Driver implements all interfaces of CSI drivers
@@ -102,6 +118,8 @@ type Driver struct {
102
118
defaultOnDeletePolicy string
103
119
removeArchivedVolumePath bool
104
120
enableWindowsHostProcess bool
121
+ kubeconfig string
122
+ kubeClient kubernetes.Interface
105
123
}
106
124
107
125
// NewDriver Creates a NewCSIDriver object. Assumes vendor version is equal to driver version &
@@ -116,6 +134,7 @@ func NewDriver(options *DriverOptions) *Driver {
116
134
driver .removeArchivedVolumePath = options .RemoveArchivedVolumePath
117
135
driver .workingMountDir = options .WorkingMountDir
118
136
driver .enableWindowsHostProcess = options .EnableWindowsHostProcess
137
+ driver .kubeconfig = options .Kubeconfig
119
138
driver .volumeLocks = newVolumeLocks ()
120
139
121
140
driver .krb5CacheDirectory = options .Krb5CacheDirectory
@@ -138,6 +157,15 @@ func NewDriver(options *DriverOptions) *Driver {
138
157
if driver .volDeletionCache , err = azcache .NewTimedCache (time .Minute , getter , false ); err != nil {
139
158
klog .Fatalf ("%v" , err )
140
159
}
160
+
161
+ kubeCfg , err := getKubeConfig (driver .kubeconfig , driver .enableWindowsHostProcess )
162
+ if err == nil && kubeCfg != nil {
163
+ if driver .kubeClient , err = kubernetes .NewForConfig (kubeCfg ); err != nil {
164
+ klog .Warningf ("NewForConfig failed with error: %v" , err )
165
+ }
166
+ } else {
167
+ klog .Warningf ("get kubeconfig(%s) failed with error: %v" , driver .kubeconfig , err )
168
+ }
141
169
return & driver
142
170
}
143
171
@@ -189,6 +217,24 @@ func (d *Driver) Run(endpoint, _ string, testMode bool) {
189
217
s .Wait ()
190
218
}
191
219
220
+ // GetUserNamePasswordFromSecret get storage account key from k8s secret
221
+ // return <username, password, domain, error>
222
+ func (d * Driver ) GetUserNamePasswordFromSecret (ctx context.Context , secretName , secretNamespace string ) (string , string , string , error ) {
223
+ if d .kubeClient == nil {
224
+ return "" , "" , "" , fmt .Errorf ("could not username and password from secret(%s): KubeClient is nil" , secretName )
225
+ }
226
+
227
+ secret , err := d .kubeClient .CoreV1 ().Secrets (secretNamespace ).Get (ctx , secretName , metav1.GetOptions {})
228
+ if err != nil {
229
+ return "" , "" , "" , fmt .Errorf ("could not get secret(%v): %v" , secretName , err )
230
+ }
231
+
232
+ username := strings .TrimSpace (string (secret .Data [usernameField ][:]))
233
+ password := strings .TrimSpace (string (secret .Data [passwordField ][:]))
234
+ domain := strings .TrimSpace (string (secret .Data [domainField ][:]))
235
+ return username , password , domain , nil
236
+ }
237
+
192
238
func IsCorruptedDir (dir string ) bool {
193
239
_ , pathErr := mount .PathExists (dir )
194
240
return pathErr != nil && mount .IsCorruptedMnt (pathErr )
@@ -279,3 +325,61 @@ func getRootDir(path string) string {
279
325
parts := strings .Split (path , "/" )
280
326
return parts [0 ]
281
327
}
328
+
329
+ func getKubeConfig (kubeconfig string , enableWindowsHostProcess bool ) (config * rest.Config , err error ) {
330
+ if kubeconfig != "" {
331
+ if config , err = clientcmd .BuildConfigFromFlags ("" , kubeconfig ); err != nil {
332
+ return nil , err
333
+ }
334
+ } else {
335
+ if config , err = inClusterConfig (enableWindowsHostProcess ); err != nil {
336
+ return nil , err
337
+ }
338
+ }
339
+ return config , err
340
+ }
341
+
342
+ // inClusterConfig is copied from https://github.com/kubernetes/client-go/blob/b46677097d03b964eab2d67ffbb022403996f4d4/rest/config.go#L507-L541
343
+ // When using Windows HostProcess containers, the path "/var/run/secrets/kubernetes.io/serviceaccount/" is under host, not container.
344
+ // Then the token and ca.crt files would be not found.
345
+ // An environment variable $CONTAINER_SANDBOX_MOUNT_POINT is set upon container creation and provides the absolute host path to the container volume.
346
+ // See https://kubernetes.io/docs/tasks/configure-pod-container/create-hostprocess-pod/#volume-mounts for more details.
347
+ func inClusterConfig (enableWindowsHostProcess bool ) (* rest.Config , error ) {
348
+ var (
349
+ tokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token"
350
+ rootCAFile = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
351
+ )
352
+ if enableWindowsHostProcess {
353
+ containerSandboxMountPath := os .Getenv ("CONTAINER_SANDBOX_MOUNT_POINT" )
354
+ if len (containerSandboxMountPath ) == 0 {
355
+ return nil , errors .New ("unable to load in-cluster configuration, containerSandboxMountPath must be defined" )
356
+ }
357
+ tokenFile = filepath .Join (containerSandboxMountPath , tokenFile )
358
+ rootCAFile = filepath .Join (containerSandboxMountPath , rootCAFile )
359
+ }
360
+
361
+ host , port := os .Getenv ("KUBERNETES_SERVICE_HOST" ), os .Getenv ("KUBERNETES_SERVICE_PORT" )
362
+ if len (host ) == 0 || len (port ) == 0 {
363
+ return nil , rest .ErrNotInCluster
364
+ }
365
+
366
+ token , err := os .ReadFile (tokenFile )
367
+ if err != nil {
368
+ return nil , err
369
+ }
370
+
371
+ tlsClientConfig := rest.TLSClientConfig {}
372
+
373
+ if _ , err := certutil .NewPool (rootCAFile ); err != nil {
374
+ klog .Errorf ("Expected to load root CA config from %s, but got err: %v" , rootCAFile , err )
375
+ } else {
376
+ tlsClientConfig .CAFile = rootCAFile
377
+ }
378
+
379
+ return & rest.Config {
380
+ Host : "https://" + net .JoinHostPort (host , port ),
381
+ TLSClientConfig : tlsClientConfig ,
382
+ BearerToken : string (token ),
383
+ BearerTokenFile : tokenFile ,
384
+ }, nil
385
+ }
0 commit comments