Skip to content

Commit 6a4d38d

Browse files
committed
feat: Split controller and node mode, add max volumes per node flag
BREAKING CHANGE: switched flag library, renamed flags and introduced mode argument
1 parent f86537c commit 6a4d38d

File tree

13 files changed

+337
-70
lines changed

13 files changed

+337
-70
lines changed

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
CMDS=cloudstack-csi-driver cloudstack-csi-sc-syncer
22

3+
PKG=github.com/leaseweb/cloudstack-csi-driver
34
# Revision that gets built into each binary via the main.version
45
# string. Uses the `git describe` output based on the most recent
56
# version tag with a short revision suffix or, if nothing has been
@@ -8,10 +9,12 @@ CMDS=cloudstack-csi-driver cloudstack-csi-sc-syncer
89
# Beware that tags may also be missing in shallow clones as done by
910
# some CI systems (like TravisCI, which pulls only 50 commits).
1011
REV=$(shell git describe --long --tags --match='v*' --dirty 2>/dev/null || git rev-list -n1 HEAD)
12+
GIT_COMMIT?=$(shell git rev-parse HEAD)
13+
BUILD_DATE?=$(shell date -u -Iseconds)
1114

1215
DOCKER?=docker
1316

14-
IMPORTPATH_LDFLAGS = -X main.version=$(REV)
17+
IMPORTPATH_LDFLAGS = -X ${PKG}/pkg/driver.driverVersion=$(REV) -X ${PKG}/pkg/driver.gitCommit=${GIT_COMMIT} -X ${PKG}/pkg/driver.buildDate=${BUILD_DATE}
1518
LDFLAGS = -s -w
1619
FULL_LDFLAGS = $(LDFLAGS) $(IMPORTPATH_LDFLAGS)
1720

charts/cloudstack-csi/templates/csi-controller-deploy.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ spec:
4343
image: "{{ .Values.controller.csiDriverController.image.repository }}:{{ .Values.controller.csiDriverController.image.tag | default .Chart.AppVersion }}"
4444
imagePullPolicy: {{ .Values.controller.csiDriverController.image.pullPolicy }}
4545
args:
46+
- "controller"
4647
- "--endpoint=$(CSI_ENDPOINT)"
47-
- "--cloudstackconfig=$(CLOUD_CONFIG)"
48+
- "--cloudstack-config=$(CLOUD_CONFIG)"
4849
- "--logging-format={{ .Values.logFormat }}"
4950
- "--v={{ .Values.logVerbosityLevel }}"
5051
{{- if .Values.controller.csiDriverController.extraArgs }}

charts/cloudstack-csi/templates/csi-node-ds.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ spec:
3131
image: "{{ .Values.node.csiDriver.image.repository }}:{{ .Values.node.csiDriver.image.tag | default .Chart.AppVersion }}"
3232
imagePullPolicy: {{ .Values.node.csiDriver.image.pullPolicy }}
3333
args:
34+
- "node"
3435
- "--endpoint=$(CSI_ENDPOINT)"
35-
- "--cloudstackconfig=$(CLOUD_CONFIG)"
36+
- "--cloudstack-config=$(CLOUD_CONFIG)"
3637
- "--logging-format={{ .Values.logFormat }}"
37-
- "--nodeName=$(NODE_NAME)"
38+
- "--node-name=$(NODE_NAME)"
3839
- "--v={{ .Values.logVerbosityLevel }}"
3940
{{- if .Values.node.csiDriver.extraArgs }}
4041
{{- with .Values.node.csiDriver.extraArgs }}

cmd/cloudstack-csi-driver/main.go

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ package main
77

88
import (
99
"context"
10-
"flag"
1110
"fmt"
1211
"os"
13-
"path"
12+
"strings"
1413

14+
flag "github.com/spf13/pflag"
1515
"k8s.io/component-base/featuregate"
1616
"k8s.io/component-base/logs"
1717
logsapi "k8s.io/component-base/logs/api/v1"
@@ -22,30 +22,51 @@ import (
2222
"github.com/leaseweb/cloudstack-csi-driver/pkg/driver"
2323
)
2424

25-
var (
26-
endpoint = flag.String("endpoint", "unix:///tmp/csi.sock", "CSI endpoint")
27-
cloudstackconfig = flag.String("cloudstackconfig", "./cloud-config", "CloudStack configuration file")
28-
nodeName = flag.String("nodeName", "", "Node name")
29-
showVersion = flag.Bool("version", false, "Show version")
30-
31-
// Version is set by the build process.
32-
version = ""
33-
)
34-
3525
func main() {
26+
fs := flag.NewFlagSet("cloudstack-csi-driver", flag.ExitOnError)
3627
if err := logsapi.RegisterLogFormat(logsapi.JSONLogFormat, json.Factory{}, logsapi.LoggingBetaOptions); err != nil {
3728
klog.ErrorS(err, "failed to register JSON log format")
3829
}
3930

31+
var (
32+
showVersion = fs.Bool("version", false, "Show version")
33+
args = os.Args[1:]
34+
cmd = string(driver.AllMode)
35+
options = driver.Options{}
36+
)
4037
fg := featuregate.NewFeatureGate()
4138
err := logsapi.AddFeatureGates(fg)
4239
if err != nil {
4340
klog.ErrorS(err, "failed to add feature gates")
4441
}
4542

4643
c := logsapi.NewLoggingConfiguration()
47-
logsapi.AddGoFlags(c, flag.CommandLine)
48-
flag.Parse()
44+
logsapi.AddFlags(c, fs)
45+
46+
if len(os.Args) > 1 && !strings.HasPrefix(os.Args[1], "-") {
47+
cmd = os.Args[1]
48+
args = os.Args[2:]
49+
}
50+
51+
switch cmd {
52+
case string(driver.ControllerMode), string(driver.NodeMode), string(driver.AllMode):
53+
options.Mode = driver.Mode(cmd)
54+
default:
55+
klog.Errorf("Unknown driver mode %s: Expected %s, %s, or %s", cmd, driver.ControllerMode, driver.NodeMode, driver.AllMode)
56+
klog.FlushAndExit(klog.ExitFlushTimeout, 0)
57+
}
58+
59+
options.AddFlags(fs)
60+
61+
if err = fs.Parse(args); err != nil {
62+
klog.ErrorS(err, "Failed to parse options")
63+
klog.FlushAndExit(klog.ExitFlushTimeout, 0)
64+
}
65+
if err = options.Validate(); err != nil {
66+
klog.ErrorS(err, "Invalid options")
67+
klog.FlushAndExit(klog.ExitFlushTimeout, 0)
68+
}
69+
4970
logs.InitLogs()
5071
logger := klog.Background()
5172
if err = logsapi.ValidateAndApply(c, fg); err != nil {
@@ -54,23 +75,27 @@ func main() {
5475
}
5576

5677
if *showVersion {
57-
baseName := path.Base(os.Args[0])
58-
fmt.Println(baseName, version) //nolint:forbidigo
78+
versionInfo, versionErr := driver.GetVersionJSON()
79+
if versionErr != nil {
80+
logger.Error(err, "failed to get version")
81+
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
82+
}
83+
fmt.Println(versionInfo) //nolint:forbidigo
5984
os.Exit(0)
6085
}
6186

6287
// Setup cloud connector.
63-
config, err := cloud.ReadConfig(*cloudstackconfig)
88+
config, err := cloud.ReadConfig(options.CloudStackConfig)
6489
if err != nil {
6590
logger.Error(err, "Cannot read CloudStack configuration")
6691
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
6792
}
68-
logger.Info("Successfully read CloudStack configuration", "cloudstackconfig", *cloudstackconfig)
93+
logger.Info("Successfully read CloudStack configuration", "cloudstackconfig", options.CloudStackConfig)
6994

7095
ctx := klog.NewContext(context.Background(), logger)
7196
csConnector := cloud.New(config)
7297

73-
d, err := driver.New(*endpoint, csConnector, nil, *nodeName, version)
98+
d, err := driver.New(ctx, csConnector, &options, nil)
7499
if err != nil {
75100
logger.Error(err, "Failed to initialize driver")
76101
klog.FlushAndExit(klog.ExitFlushTimeout, 1)

deploy/k8s/controller-deployment.yaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ spec:
3737
image: cloudstack-csi-driver
3838
imagePullPolicy: Always
3939
args:
40-
- "-endpoint=$(CSI_ENDPOINT)"
41-
- "-cloudstackconfig=/etc/cloudstack-csi-driver/cloud-config"
42-
- "-logging-format=text"
43-
- "-v=4"
40+
- "controller"
41+
- "--endpoint=$(CSI_ENDPOINT)"
42+
- "--cloudstack-config=/etc/cloudstack-csi-driver/cloud-config"
43+
- "--logging-format=text"
44+
- "--v=4"
4445
env:
4546
- name: CSI_ENDPOINT
4647
value: unix:///var/lib/csi/sockets/pluginproxy/csi.sock

deploy/k8s/node-daemonset.yaml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,12 @@ spec:
2929
image: cloudstack-csi-driver
3030
imagePullPolicy: Always
3131
args:
32-
- "-endpoint=$(CSI_ENDPOINT)"
33-
- "-cloudstackconfig=/etc/cloudstack-csi-driver/cloud-config"
34-
- "-logging-format=text"
35-
- "-nodeName=$(NODE_NAME)"
36-
- "-v=4"
32+
- "node"
33+
- "--endpoint=$(CSI_ENDPOINT)"
34+
- "--cloudstack-config=/etc/cloudstack-csi-driver/cloud-config"
35+
- "--logging-format=text"
36+
- "--node-name=$(NODE_NAME)"
37+
- "--v=4"
3738
env:
3839
- name: CSI_ENDPOINT
3940
value: unix:///csi/csi.sock

pkg/driver/constants.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,38 @@ package driver
33
// DriverName is the name of the CSI plugin.
44
const DriverName = "csi.cloudstack.apache.org"
55

6+
// Mode is the operating mode of the CSI driver.
7+
type Mode string
8+
9+
// Driver operating modes.
10+
const (
11+
// ControllerMode is the mode that only starts the controller service.
12+
ControllerMode Mode = "controller"
13+
// NodeMode is the mode that only starts the node service.
14+
NodeMode Mode = "node"
15+
// AllMode is the mode that only starts both the controller and the node service.
16+
AllMode Mode = "all"
17+
)
18+
19+
// constants for default command line flag values.
20+
const (
21+
// DefaultCSIEndpoint is the default CSI endpoint for the driver.
22+
DefaultCSIEndpoint = "unix://tmp/csi.sock"
23+
DefaultMaxVolAttachLimit int64 = 256
24+
)
25+
26+
// Filesystem types.
27+
const (
28+
// FSTypeExt2 represents the ext2 filesystem type.
29+
FSTypeExt2 = "ext2"
30+
// FSTypeExt3 represents the ext3 filesystem type.
31+
FSTypeExt3 = "ext3"
32+
// FSTypeExt4 represents the ext4 filesystem type.
33+
FSTypeExt4 = "ext4"
34+
// FSTypeXfs represents the xfs filesystem type.
35+
FSTypeXfs = "xfs"
36+
)
37+
638
// Topology keys.
739
const (
840
ZoneKey = "topology." + DriverName + "/zone"

pkg/driver/driver.go

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ package driver
55

66
import (
77
"context"
8+
"fmt"
9+
10+
"github.com/container-storage-interface/spec/lib/go/csi"
11+
"k8s.io/klog/v2"
812

913
"github.com/leaseweb/cloudstack-csi-driver/pkg/cloud"
1014
"github.com/leaseweb/cloudstack-csi-driver/pkg/mount"
@@ -17,29 +21,49 @@ type Interface interface {
1721
}
1822

1923
type cloudstackDriver struct {
20-
endpoint string
21-
nodeName string
22-
version string
23-
24-
connector cloud.Interface
25-
mounter mount.Interface
24+
controller csi.ControllerServer
25+
identity csi.IdentityServer
26+
node csi.NodeServer
27+
options *Options
2628
}
2729

2830
// New instantiates a new CloudStack CSI driver.
29-
func New(endpoint string, csConnector cloud.Interface, mounter mount.Interface, nodeName string, version string) (Interface, error) {
30-
return &cloudstackDriver{
31-
endpoint: endpoint,
32-
nodeName: nodeName,
33-
version: version,
34-
connector: csConnector,
35-
mounter: mounter,
36-
}, nil
31+
func New(ctx context.Context, csConnector cloud.Interface, options *Options, mounter mount.Interface) (Interface, error) {
32+
logger := klog.FromContext(ctx)
33+
logger.Info("Driver starting", "Driver", DriverName, "Version", driverVersion)
34+
35+
if err := validateMode(options.Mode); err != nil {
36+
return nil, fmt.Errorf("invalid driver options: %w", err)
37+
}
38+
39+
driver := &cloudstackDriver{
40+
options: options,
41+
}
42+
43+
driver.identity = NewIdentityServer(driverVersion)
44+
switch options.Mode {
45+
case ControllerMode:
46+
driver.controller = NewControllerServer(csConnector)
47+
case NodeMode:
48+
driver.node = NewNodeServer(csConnector, mounter, options)
49+
case AllMode:
50+
driver.controller = NewControllerServer(csConnector)
51+
driver.node = NewNodeServer(csConnector, mounter, options)
52+
default:
53+
return nil, fmt.Errorf("unknown mode: %s", options.Mode)
54+
}
55+
56+
return driver, nil
3757
}
3858

3959
func (cs *cloudstackDriver) Run(ctx context.Context) error {
40-
ids := NewIdentityServer(cs.version)
41-
ctrls := NewControllerServer(cs.connector)
42-
ns := NewNodeServer(cs.connector, cs.mounter, cs.nodeName)
60+
return cs.serve(ctx)
61+
}
62+
63+
func validateMode(mode Mode) error {
64+
if mode != AllMode && mode != ControllerMode && mode != NodeMode {
65+
return fmt.Errorf("mode is not supported (actual: %s, supported: %v)", mode, []Mode{AllMode, ControllerMode, NodeMode})
66+
}
4367

44-
return cs.serve(ctx, ids, ctrls, ns)
68+
return nil
4569
}

pkg/driver/node.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,30 @@ import (
1919

2020
const (
2121
// default file system type to be used when it is not provided.
22-
defaultFsType = "ext4"
22+
defaultFsType = FSTypeExt4
2323
)
2424

2525
type nodeServer struct {
2626
csi.UnimplementedNodeServer
27-
connector cloud.Interface
28-
mounter mount.Interface
29-
nodeName string
30-
volumeLocks *util.VolumeLocks
27+
connector cloud.Interface
28+
mounter mount.Interface
29+
maxVolumesPerNode int64
30+
nodeName string
31+
volumeLocks *util.VolumeLocks
3132
}
3233

3334
// NewNodeServer creates a new Node gRPC server.
34-
func NewNodeServer(connector cloud.Interface, mounter mount.Interface, nodeName string) csi.NodeServer {
35+
func NewNodeServer(connector cloud.Interface, mounter mount.Interface, options *Options) csi.NodeServer {
3536
if mounter == nil {
3637
mounter = mount.New()
3738
}
3839

3940
return &nodeServer{
40-
connector: connector,
41-
mounter: mounter,
42-
nodeName: nodeName,
43-
volumeLocks: util.NewVolumeLocks(),
41+
connector: connector,
42+
mounter: mounter,
43+
maxVolumesPerNode: options.VolumeAttachLimit,
44+
nodeName: options.NodeName,
45+
volumeLocks: util.NewVolumeLocks(),
4446
}
4547
}
4648

@@ -392,6 +394,7 @@ func (ns *nodeServer) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoReque
392394
return &csi.NodeGetInfoResponse{
393395
NodeId: vm.ID,
394396
AccessibleTopology: topology.ToCSI(),
397+
MaxVolumesPerNode: ns.maxVolumesPerNode,
395398
}, nil
396399
}
397400

0 commit comments

Comments
 (0)