Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VMware Support #9

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
38a249d
Add ProjectID and DomainID for creating volumes
schlapzz Jul 21, 2021
5fe6f87
update README.md
schlapzz Jul 21, 2021
0d02f07
add hypervisor to volumes, add rescan with script, find disk by path …
schlapzz Aug 3, 2021
9f2b2b5
clean scsi disks on bus in unstage volume
schlapzz Aug 4, 2021
99ed163
clean scsi disks on bus in unpublish volume on node
schlapzz Aug 4, 2021
c95cdfb
add max allowed volumes check
schlapzz Aug 4, 2021
89a40cb
fix error
schlapzz Aug 4, 2021
7d2a8a3
better log statements, add project id for listing volumes
schlapzz Aug 4, 2021
ffb2762
add rescan with echo command, better log statements, check max volume…
schlapzz Aug 5, 2021
702e276
use script for cleaning scsi bus
schlapzz Aug 6, 2021
685b37b
add mutex to avoid race conditions while attaching volume
schlapzz Aug 6, 2021
dd9d074
add volume stats capability
schlapzz Aug 6, 2021
f57d5b3
add env. variable for hypervisor
schlapzz Aug 6, 2021
2b1420e
update README.md
schlapzz Aug 6, 2021
812f683
update github actions to swisstxt values
schlapzz Aug 9, 2021
237862e
remove .idea folder
schlapzz Aug 9, 2021
44db10a
update readme for reusing volumes
schlapzz Aug 9, 2021
d78034a
make max volumes per node configurable
schlapzz Aug 14, 2021
3a22f7e
update readme and daemonset, get max vol per node from env. var. if set
schlapzz Aug 19, 2021
111215e
Merge branch 'master' into feature/cargo-55
schlapzz Oct 9, 2021
55bfbbf
Merge pull request #1 from swisstxt/feature/cargo-55
schlapzz Oct 9, 2021
15d20c0
reverts swisstxt specific parts
schlapzz Mar 29, 2022
9e19bb9
reverts swisstxt specific parts
schlapzz Mar 29, 2022
63c8c53
reverts swisstxt specific parts
schlapzz Mar 29, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/bin
/test/e2e/e2e.test
/test/e2e/ginkgo
/cloudstack.ini
/.idea
cloud-config
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ api-url = <CloudStack API URL>
api-key = <CloudStack API Key>
secret-key = <CloudStack API Secret>
ssl-no-verify = <Disable SSL certificate validation: true or false (optional)>
project-id = <project ID>
```

Create a secret named `cloudstack-secret` in namespace `kube-system`:
Expand All @@ -51,6 +52,18 @@ kubectl create secret generic \
cloudstack-secret
```

Set the correct hypervisor in the DaemonSet Env Vars:
```
- name: NODE_HYPERVISOR
value: vmware
```

You can manually set the maximal attachable number of block volumes per node:
```
- name: NODE_MAX_BLOCK_VOLUMES
value: "15" #Default value is 10 volumes per node
```

If you have also deployed the [CloudStack Kubernetes Provider](https://github.com/apache/cloudstack-kubernetes-provider),
you may use the same secret for both tools.

Expand Down Expand Up @@ -88,11 +101,19 @@ disk offerings to Kubernetes storage classes.

Example:

```
```bash
kubectl apply -f ./examples/k8s/pvc.yaml
kubectl apply -f ./examples/k8s/pod.yaml
```

#### Reusing volumes

1. Patch PV `reclaimPolicy` with `kubectl patch pv my-pv-name -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'`
2. Delete Old Pod and PVC
3. Patch PV `claimRef` with `kubectl patch pv my-pv-name -p '{"spec":{"claimRef": null}}'`
4. Create new Pod and PVC with existing claimName `.spec.claimRef.name = my-pv-name`


## Building

To build the driver binary:
Expand Down
2 changes: 2 additions & 0 deletions clean-scsi-bus.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
echo 1 > /sys/class/scsi_device/0\:0\:$1\:0/device/delete
8 changes: 7 additions & 1 deletion cmd/cloudstack-csi-driver/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ RUN apk add --no-cache \
# Provides mkfs.xfs
xfsprogs \
# Provides blkid, also used by k8s.io/mount-utils
blkid
blkid \
eudev \
bash

COPY ./bin/cloudstack-csi-driver /cloudstack-csi-driver
COPY rescan-scsi-bus.sh /usr/bin/
RUN chmod +x /usr/bin/rescan-scsi-bus.sh
COPY clean-scsi-bus.sh /usr/bin/
RUN chmod +x /usr/bin/clean-scsi-bus.sh
ENTRYPOINT ["/cloudstack-csi-driver"]
145 changes: 89 additions & 56 deletions deploy/k8s/node-daemonset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,101 +2,134 @@ apiVersion: apps/v1
kind: DaemonSet
metadata:
name: cloudstack-csi-node
namespace: kube-system
spec:
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/name: cloudstack-csi-node
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app.kubernetes.io/name: cloudstack-csi-node
app.kubernetes.io/part-of: cloudstack-csi-driver
spec:
nodeSelector:
kubernetes.io/os: linux
tolerations:
- effect: NoExecute
operator: Exists
- effect: NoSchedule
operator: Exists

containers:
- name: cloudstack-csi-node
image: cloudstack-csi-driver
imagePullPolicy: Always
args:
- "-endpoint=$(CSI_ENDPOINT)"
- "-cloudstackconfig=/etc/cloudstack-csi-driver/cloud-config"
- "-nodeName=$(NODE_NAME)"
- "-debug"
- args:
- -endpoint=$(CSI_ENDPOINT)
- -cloudstackconfig=/etc/cloudstack-csi-driver/cloudstack.ini
- -nodeName=$(NODE_NAME)
- -debug
env:
- name: CSI_ENDPOINT
value: unix:///csi/csi.sock
- name: NODE_HYPERVISOR
value: vmware
- name: NODE_MAX_BLOCK_VOLUMES
value: "10"
- name: NODE_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
image: cloudstack-csi-driver
imagePullPolicy: Always
name: cloudstack-csi-node
resources: {}
securityContext:
privileged: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- name: plugin-dir
mountPath: /csi
- name: kubelet-dir
mountPath: /var/lib/kubelet
# needed so that any mounts setup inside this container are
# propagated back to the host machine.
mountPropagation: Bidirectional
- name: device-dir
mountPath: /dev
- name: cloud-init-dir
mountPath: /run/cloud-init/
- name: cloudstack-conf
mountPath: /etc/cloudstack-csi-driver

- name: node-driver-registrar
image: k8s.gcr.io/sig-storage/csi-node-driver-registrar:v2.0.1
imagePullPolicy: IfNotPresent
args:
- "--csi-address=$(ADDRESS)"
- "--kubelet-registration-path=$(DRIVER_REG_SOCK_PATH)"
- "--v=5"
- mountPath: /csi
name: plugin-dir
- mountPath: /var/lib/kubelet
mountPropagation: Bidirectional
name: kubelet-dir
- mountPath: /dev
name: device-dir
- mountPath: /run/cloud-init/
name: cloud-init-dir
- mountPath: /etc/cloudstack-csi-driver
name: cloudstack-conf
- mountPath: /sys/class/scsi_host/
name: sys-class-scsi-host-dir
- mountPath: /sys/class/scsi_device/
name: sys-class-scsi-device-dir
- mountPath: /sys/devices
name: sys-devices
- args:
- --csi-address=$(ADDRESS)
- --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH)
- --v=5
env:
- name: ADDRESS
value: /csi/csi.sock
- name: DRIVER_REG_SOCK_PATH
value: /var/lib/kubelet/plugins/csi.cloudstack.apache.org/csi.sock
image: k8s.gcr.io/sig-storage/csi-node-driver-registrar:v2.0.1
imagePullPolicy: IfNotPresent
name: node-driver-registrar
resources: {}
securityContext:
privileged: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- name: plugin-dir
mountPath: /csi
- name: registration-dir
mountPath: /registration

- mountPath: /csi
name: plugin-dir
- mountPath: /registration
name: registration-dir
dnsPolicy: ClusterFirst
nodeSelector:
kubernetes.io/os: linux
restartPolicy: Always
schedulerName: default-scheduler
serviceAccount: cloudstack-csi-node
serviceAccountName: cloudstack-csi-node
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
operator: Exists
- effect: NoSchedule
operator: Exists
volumes:
- name: plugin-dir
hostPath:
- hostPath:
path: /var/lib/kubelet/plugins/csi.cloudstack.apache.org/
type: DirectoryOrCreate
- name: kubelet-dir
hostPath:
name: plugin-dir
- hostPath:
path: /var/lib/kubelet
type: Directory
- name: device-dir
hostPath:
name: kubelet-dir
- hostPath:
path: /dev
type: Directory
- name: registration-dir
hostPath:
name: device-dir
- hostPath:
path: /var/lib/kubelet/plugins_registry
type: Directory
- name: cloud-init-dir
hostPath:
name: registration-dir
- hostPath:
path: /run/cloud-init/
type: Directory
name: cloud-init-dir
- hostPath:
path: /sys/class/scsi_host
type: Directory
name: sys-class-scsi-host-dir
- hostPath:
path: /sys/class/scsi_device
type: Directory
name: sys-class-scsi-device-dir
- hostPath:
path: /sys/devices
type: Directory
name: sys-devices
- name: cloudstack-conf
secret:
secretName: cloudstack-secret
defaultMode: 420
secretName: csi-cloudstack-secret
updateStrategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/hashicorp/go-uuid v1.0.2
github.com/kubernetes-csi/csi-test/v4 v4.2.0
go.uber.org/zap v1.16.0
golang.org/x/sys v0.0.0-20210510120138-977fb7262007
golang.org/x/text v0.3.6
google.golang.org/genproto v0.0.0-20210726200206-e7812ac95cc0 // indirect
google.golang.org/grpc v1.39.0
Expand Down
10 changes: 8 additions & 2 deletions pkg/cloud/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@ type Interface interface {

ListZonesID(ctx context.Context) ([]string, error)

GetDomainID(ctx context.Context) (string, error)
GetProjectID() string

GetVolumeByID(ctx context.Context, volumeID string) (*Volume, error)
GetVolumeByName(ctx context.Context, name string) (*Volume, error)
CreateVolume(ctx context.Context, diskOfferingID, zoneID, name string, sizeInGB int64) (string, error)
ListVolumesForVM(ctx context.Context, virtualMachineID, projectID string) ([]*Volume, error)
CreateVolume(ctx context.Context, diskOfferingID, projectID, domainID, zoneID, name string, sizeInGB int64) (string, error)
DeleteVolume(ctx context.Context, id string) error
AttachVolume(ctx context.Context, volumeID, vmID string) (string, error)
DetachVolume(ctx context.Context, volumeID string) error
Expand All @@ -37,6 +41,7 @@ type Volume struct {

VirtualMachineID string
DeviceID string
Hypervisor string
}

// VM represents a CloudStack Virtual Machine.
Expand All @@ -54,10 +59,11 @@ var (
// client is the implementation of Interface.
type client struct {
*cloudstack.CloudStackClient
ProjectID string
}

// New creates a new cloud connector, given its configuration.
func New(config *Config) Interface {
csClient := cloudstack.NewAsyncClient(config.APIURL, config.APIKey, config.SecretKey, config.VerifySSL)
return &client{csClient}
return &client{csClient, config.ProjectID}
}
2 changes: 2 additions & 0 deletions pkg/cloud/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Config struct {
APIKey string
SecretKey string
VerifySSL bool
ProjectID string
}

// csConfig wraps the config for the CloudStack cloud provider.
Expand Down Expand Up @@ -42,5 +43,6 @@ func ReadConfig(configFilePath string) (*Config, error) {
APIKey: cfg.Global.APIKey,
SecretKey: cfg.Global.SecretKey,
VerifySSL: cfg.Global.SSLNoVerify,
ProjectID: cfg.Global.ProjectID,
}, nil
}
10 changes: 9 additions & 1 deletion pkg/cloud/fake/fake.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (f *fakeConnector) GetVolumeByName(ctx context.Context, name string) (*clou
return nil, cloud.ErrNotFound
}

func (f *fakeConnector) CreateVolume(ctx context.Context, diskOfferingID, zoneID, name string, sizeInGB int64) (string, error) {
func (f *fakeConnector) CreateVolume(ctx context.Context, diskOfferingID, projectID, domainID, zoneID, name string, sizeInGB int64) (string, error) {
id, _ := uuid.GenerateUUID()
vol := cloud.Volume{
ID: id,
Expand Down Expand Up @@ -101,3 +101,11 @@ func (f *fakeConnector) AttachVolume(ctx context.Context, volumeID, vmID string)
}

func (f *fakeConnector) DetachVolume(ctx context.Context, volumeID string) error { return nil }

func (f *fakeConnector) GetDomainID(ctx context.Context) (string, error) {
return "domain", nil
}

func (f *fakeConnector) GetProjectID() string {
return "test"
}
23 changes: 23 additions & 0 deletions pkg/cloud/project.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package cloud

import (
"context"
"github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap"
)

func (c *client) GetDomainID(ctx context.Context) (string, error) {
p, _, err := c.Project.GetProjectByID(c.ProjectID)
ctxzap.Extract(ctx).Sugar().Infow("CloudStack API call", "command", "GetProjectByID", "params", map[string]string{
"projectID": c.ProjectID,
})

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

return p.Domainid, nil
}

func (c *client) GetProjectID() string {
return c.ProjectID
}
1 change: 1 addition & 0 deletions pkg/cloud/vms.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func (c *client) GetVMByID(ctx context.Context, vmID string) (*VM, error) {
return nil, ErrTooManyResults
}
vm := l.VirtualMachines[0]

return &VM{
ID: vm.Id,
ZoneID: vm.Zoneid,
Expand Down
Loading