Skip to content

Commit 7552602

Browse files
authored
Merge pull request #449 from rfranzke/feature/run-as-controller
Allow disabling particular driver services
2 parents 5bac10a + 905c1d4 commit 7552602

File tree

15 files changed

+134
-69
lines changed

15 files changed

+134
-69
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ push-container: build-container
4040
gcloud docker -- push $(STAGINGIMAGE):$(STAGINGVERSION)
4141

4242
test-sanity: gce-pd-driver
43-
go test -timeout 30s sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/test -run ^TestSanity$
43+
go test -v -timeout 30s sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/test/sanity -run ^TestSanity$
4444

4545
test-k8s-integration:
4646
go build -o bin/k8s-integration-test ./test/k8s-integration

cmd/main.go

+32-13
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ import (
3030
)
3131

3232
var (
33-
endpoint = flag.String("endpoint", "unix:/tmp/csi.sock", "CSI endpoint")
34-
gceConfigFilePath = flag.String("cloud-config", "", "Path to GCE cloud provider config")
35-
vendorVersion string
33+
cloudConfigFilePath = flag.String("cloud-config", "", "Path to GCE cloud provider config")
34+
endpoint = flag.String("endpoint", "unix:/tmp/csi.sock", "CSI endpoint")
35+
runControllerService = flag.Bool("run-controller-service", true, "If set to false then the CSI driver does not activate its controller service (default: true)")
36+
runNodeService = flag.Bool("run-node-service", true, "If set to false then the CSI driver does not activate its node service (default: true)")
37+
vendorVersion string
3638
)
3739

3840
const (
@@ -57,6 +59,8 @@ func main() {
5759
}
5860

5961
func handle() {
62+
var err error
63+
6064
if vendorVersion == "" {
6165
klog.Fatalf("vendorVersion must be set at compile time")
6266
}
@@ -68,20 +72,35 @@ func handle() {
6872
ctx, cancel := context.WithCancel(context.Background())
6973
defer cancel()
7074

71-
cloudProvider, err := gce.CreateCloudProvider(ctx, vendorVersion, *gceConfigFilePath)
72-
if err != nil {
73-
klog.Fatalf("Failed to get cloud provider: %v", err)
75+
//Initialize identity server
76+
identityServer := driver.NewIdentityServer(gceDriver)
77+
78+
//Initialize requirements for the controller service
79+
var controllerServer *driver.GCEControllerServer
80+
if *runControllerService {
81+
cloudProvider, err := gce.CreateCloudProvider(ctx, vendorVersion, *cloudConfigFilePath)
82+
if err != nil {
83+
klog.Fatalf("Failed to get cloud provider: %v", err)
84+
}
85+
controllerServer = driver.NewControllerServer(gceDriver, cloudProvider)
86+
} else if *cloudConfigFilePath != "" {
87+
klog.Warningf("controller service is disabled but cloud config given - it has no effect")
7488
}
7589

76-
mounter := mountmanager.NewSafeMounter()
77-
deviceUtils := mountmanager.NewDeviceUtils()
78-
statter := mountmanager.NewStatter()
79-
ms, err := metadataservice.NewMetadataService()
80-
if err != nil {
81-
klog.Fatalf("Failed to set up metadata service: %v", err)
90+
//Initialize requirements for the node service
91+
var nodeServer *driver.GCENodeServer
92+
if *runNodeService {
93+
mounter := mountmanager.NewSafeMounter()
94+
deviceUtils := mountmanager.NewDeviceUtils()
95+
statter := mountmanager.NewStatter()
96+
meta, err := metadataservice.NewMetadataService()
97+
if err != nil {
98+
klog.Fatalf("Failed to set up metadata service: %v", err)
99+
}
100+
nodeServer = driver.NewNodeServer(gceDriver, mounter, deviceUtils, meta, statter)
82101
}
83102

84-
err = gceDriver.SetupGCEDriver(cloudProvider, mounter, deviceUtils, ms, statter, driverName, vendorVersion)
103+
err = gceDriver.SetupGCEDriver(driverName, vendorVersion, identityServer, controllerServer, nodeServer)
85104
if err != nil {
86105
klog.Fatalf("Failed to initialize GCE CSI Driver: %v", err)
87106
}

deploy/kubernetes/base/controller.yaml

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ spec:
1717
# since it replaces GCE Metadata Server with GKE Metadata Server. Remove
1818
# this requirement when issue is resolved and before any exposure of
1919
# metrics ports
20-
hostNetwork: true
20+
hostNetwork: true
2121
serviceAccountName: csi-gce-pd-controller-sa
2222
priorityClassName: csi-gce-pd-controller
2323
containers:
@@ -27,6 +27,8 @@ spec:
2727
- "--v=5"
2828
- "--csi-address=/csi/csi.sock"
2929
- "--feature-gates=Topology=true"
30+
# - "--run-controller-service=false" # disable the controller service of the CSI driver
31+
# - "--run-node-service=false" # disable the node service of the CSI driver
3032
volumeMounts:
3133
- name: socket-dir
3234
mountPath: /csi

docs/kubernetes/user-guides/driver-install.md

+20-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ compute.instances.get
1818
compute.instances.attachDisk
1919
compute.instances.detachDisk
2020
roles/compute.storageAdmin
21-
roles/iam.serviceAccountUser
21+
roles/iam.serviceAccountUser
2222
```
2323

2424
If there is a pre-existing service account with these roles for use then the
@@ -79,4 +79,22 @@ iam.serviceAccounts.delete
7979
```
8080

8181
These permissions are not required if you already have a service account ready
82-
for use by the PD Driver.
82+
for use by the PD Driver.
83+
84+
## Disabling particular CSI driver services
85+
86+
Traditionally, you run the CSI controllers with the GCE PD driver in the same Kubernetes cluster.
87+
Though, there may be cases where you will only want to run a subset of the available driver services (for example, one scenario is running the controllers outside of the cluster they are serving (while the GCE PD driver still runs inside the served cluster), but there might be others scenarios).
88+
The CSI driver consists out of these services:
89+
90+
* The **controller** service starts the GRPC server that serves `CreateVolume`, `DeleteVolume`, etc. It is depending on the GCP service account credentials and talks with the GCP API.
91+
* The **identity** service is responsible to provide identity services like capability information of the CSI plugin.
92+
* The **node** service implements the various operations for volumes that are run locally from the node, for example `NodePublishVolume`, `NodeStageVolume`, etc. It does not do operations like `CreateVolume` or `ControllerPublish`. Also, as it runs directly on the GCE instances, it is depending on the GCE metadata service.
93+
94+
The CSI driver has two command line flags, `--run-controller-service` and `--run-node-service` which both default to `true`.
95+
You can disable the individual services by setting the respective flags to `false`.
96+
97+
Note: If you want to run the CSI controllers outside of the cluster you have to specify both the `zone` and `projectId` parameters in the GCE cloud provider config.
98+
The `zone` is the name of one of the availability zones the served Kubernetes cluster is deployed to.
99+
It is used to derive the GCP region and to discover the other availability zones in this region.
100+
The `project-id` is the GCP project ID in which the controller is operating.

pkg/gce-cloud-provider/compute/fake-gce.go

+8
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ func CreateFakeCloudProvider(project, zone string, cloudDisks []*CloudDisk) (*Fa
6767
return fcp, nil
6868
}
6969

70+
func (cloud *FakeCloudProvider) GetDefaultProject() string {
71+
return cloud.project
72+
}
73+
74+
func (cloud *FakeCloudProvider) GetDefaultZone() string {
75+
return cloud.zone
76+
}
77+
7078
func (cloud *FakeCloudProvider) RepairUnderspecifiedVolumeKey(ctx context.Context, volumeKey *meta.Key) (*meta.Key, error) {
7179
switch volumeKey.Type() {
7280
case meta.Zonal:

pkg/gce-cloud-provider/compute/gce-compute.go

+13
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ const (
3838
)
3939

4040
type GCECompute interface {
41+
// Metadata information
42+
GetDefaultProject() string
43+
GetDefaultZone() string
4144
// Disk Methods
4245
GetDisk(ctx context.Context, volumeKey *meta.Key) (*CloudDisk, error)
4346
RepairUnderspecifiedVolumeKey(ctx context.Context, volumeKey *meta.Key) (*meta.Key, error)
@@ -63,6 +66,16 @@ type GCECompute interface {
6366
DeleteSnapshot(ctx context.Context, snapshotName string) error
6467
}
6568

69+
// GetDefaultProject returns the project that was used to instantiate this GCE client.
70+
func (cloud *CloudProvider) GetDefaultProject() string {
71+
return cloud.project
72+
}
73+
74+
// GetDefaultZone returns the zone that was used to instantiate this GCE client.
75+
func (cloud *CloudProvider) GetDefaultZone() string {
76+
return cloud.zone
77+
}
78+
6679
// ListDisks lists disks based on maxEntries and pageToken only in the project
6780
// and zone that the driver is running in.
6881
func (cloud *CloudProvider) ListDisks(ctx context.Context, maxEntries int64, pageToken string) ([]*computev1.Disk, string, error) {

pkg/gce-cloud-provider/compute/gce.go

+11-4
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ type ConfigGlobal struct {
6666
TokenURL string `gcfg:"token-url"`
6767
TokenBody string `gcfg:"token-body"`
6868
ProjectId string `gcfg:"project-id"`
69+
Zone string `gcfg:"zone"`
6970
}
7071

7172
func CreateCloudProvider(ctx context.Context, vendorVersion string, configPath string) (*CloudProvider, error) {
@@ -103,7 +104,6 @@ func CreateCloudProvider(ctx context.Context, vendorVersion string, configPath s
103104
}
104105

105106
func generateTokenSource(ctx context.Context, configFile *ConfigFile) (oauth2.TokenSource, error) {
106-
107107
if configFile != nil && configFile.Global.TokenURL != "" && configFile.Global.TokenURL != "nil" {
108108
// configFile.Global.TokenURL is defined
109109
// Use AltTokenSource
@@ -184,9 +184,16 @@ func newOauthClient(ctx context.Context, tokenSource oauth2.TokenSource) (*http.
184184
func getProjectAndZone(config *ConfigFile) (string, string, error) {
185185
var err error
186186

187-
zone, err := metadata.Zone()
188-
if err != nil {
189-
return "", "", err
187+
var zone string
188+
if config == nil || config.Global.Zone == "" {
189+
zone, err = metadata.Zone()
190+
if err != nil {
191+
return "", "", err
192+
}
193+
klog.V(2).Infof("Using GCP zone from the Metadata server: %q", zone)
194+
} else {
195+
zone = config.Global.Zone
196+
klog.V(2).Infof("Using GCP zone from the local GCE cloud provider config file: %q", zone)
190197
}
191198

192199
var projectID string

pkg/gce-cloud-provider/metadata/fake.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ type fakeServiceManager struct{}
2121
var _ MetadataService = &fakeServiceManager{}
2222

2323
const (
24-
FakeZone = "country-region-zone"
25-
FakeSecondZone = "country-region-zone2"
26-
FakeProject = "test-project"
24+
FakeZone = "country-region-zone"
25+
FakeProject = "test-project"
2726
)
2827

2928
var FakeMachineType = "n1-standard-1"

pkg/gce-pd-csi-driver/controller.go

+6-10
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,16 @@ limitations under the License.
1515
package gceGCEDriver
1616

1717
import (
18+
"context"
1819
"fmt"
1920
"math/rand"
2021
"sort"
2122
"strings"
2223
"time"
2324

24-
"github.com/golang/protobuf/ptypes"
25-
26-
"context"
27-
2825
"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta"
2926
csi "github.com/container-storage-interface/spec/lib/go/csi"
27+
"github.com/golang/protobuf/ptypes"
3028
compute "google.golang.org/api/compute/v1"
3129
"google.golang.org/grpc/codes"
3230
"google.golang.org/grpc/status"
@@ -35,13 +33,11 @@ import (
3533

3634
"sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/common"
3735
gce "sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/gce-cloud-provider/compute"
38-
metadataservice "sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/gce-cloud-provider/metadata"
3936
)
4037

4138
type GCEControllerServer struct {
42-
Driver *GCEDriver
43-
CloudProvider gce.GCECompute
44-
MetadataService metadataservice.MetadataService
39+
Driver *GCEDriver
40+
CloudProvider gce.GCECompute
4541

4642
// A map storing all volumes with ongoing operations so that additional
4743
// operations for that same volume (as defined by Volume Key) return an
@@ -141,7 +137,7 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
141137
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("CreateVolume replication type '%s' is not supported", replicationType))
142138
}
143139

144-
volumeID, err := common.KeyToVolumeID(volKey, gceCS.MetadataService.GetProject())
140+
volumeID, err := common.KeyToVolumeID(volKey, gceCS.CloudProvider.GetDefaultProject())
145141
if err != nil {
146142
return nil, status.Errorf(codes.Internal, "Failed to convert volume key to volume ID: %v", err)
147143
}
@@ -950,7 +946,7 @@ func pickZones(ctx context.Context, gceCS *GCEControllerServer, top *csi.Topolog
950946
return nil, fmt.Errorf("failed to pick zones from topology: %v", err)
951947
}
952948
} else {
953-
zones, err = getDefaultZonesInRegion(ctx, gceCS, []string{gceCS.MetadataService.GetZone()}, numZones)
949+
zones, err = getDefaultZonesInRegion(ctx, gceCS, []string{gceCS.CloudProvider.GetDefaultZone()}, numZones)
954950
if err != nil {
955951
return nil, fmt.Errorf("failed to get default %v zones in region: %v", numZones, err)
956952
}

pkg/gce-pd-csi-driver/controller_test.go

+11-11
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@ import (
3535
csi "github.com/container-storage-interface/spec/lib/go/csi"
3636
"sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/common"
3737
gce "sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/gce-cloud-provider/compute"
38-
metadataservice "sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/gce-cloud-provider/metadata"
3938
)
4039

4140
const (
42-
project = metadataservice.FakeProject
43-
zone = metadataservice.FakeZone
44-
node = "test-node"
45-
driver = "test-driver"
46-
name = "test-name"
41+
project = "test-project"
42+
zone = "country-region-zone"
43+
secondZone = "country-region-fakesecondzone"
44+
node = "test-node"
45+
driver = "test-driver"
46+
name = "test-name"
4747
)
4848

4949
var (
@@ -56,7 +56,7 @@ var (
5656
}
5757
stdTopology = []*csi.Topology{
5858
{
59-
Segments: map[string]string{common.TopologyKeyZone: metadataservice.FakeZone},
59+
Segments: map[string]string{common.TopologyKeyZone: zone},
6060
},
6161
}
6262
testVolumeID = fmt.Sprintf("projects/%s/zones/%s/disks/%s", project, zone, name)
@@ -435,7 +435,7 @@ func TestCreateVolumeArguments(t *testing.T) {
435435
},
436436
expVol: &csi.Volume{
437437
CapacityBytes: common.GbToBytes(20),
438-
VolumeId: fmt.Sprintf("projects/%s/zones/topology-zone/disks/%s", metadataservice.FakeProject, name),
438+
VolumeId: fmt.Sprintf("projects/%s/zones/topology-zone/disks/%s", project, name),
439439
VolumeContext: nil,
440440
AccessibleTopology: []*csi.Topology{
441441
{
@@ -478,7 +478,7 @@ func TestCreateVolumeArguments(t *testing.T) {
478478
},
479479
expVol: &csi.Volume{
480480
CapacityBytes: common.GbToBytes(20),
481-
VolumeId: fmt.Sprintf("projects/%s/zones/topology-zone2/disks/%s", metadataservice.FakeProject, name),
481+
VolumeId: fmt.Sprintf("projects/%s/zones/topology-zone2/disks/%s", project, name),
482482
VolumeContext: nil,
483483
AccessibleTopology: []*csi.Topology{
484484
{
@@ -594,10 +594,10 @@ func TestCreateVolumeArguments(t *testing.T) {
594594
VolumeContext: nil,
595595
AccessibleTopology: []*csi.Topology{
596596
{
597-
Segments: map[string]string{common.TopologyKeyZone: metadataservice.FakeZone},
597+
Segments: map[string]string{common.TopologyKeyZone: zone},
598598
},
599599
{
600-
Segments: map[string]string{common.TopologyKeyZone: "country-region-fakesecondzone"},
600+
Segments: map[string]string{common.TopologyKeyZone: secondZone},
601601
},
602602
},
603603
},

pkg/gce-pd-csi-driver/gce-pd-driver.go

+10-14
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,11 @@ func GetGCEDriver() *GCEDriver {
4545
return &GCEDriver{}
4646
}
4747

48-
func (gceDriver *GCEDriver) SetupGCEDriver(cloudProvider gce.GCECompute, mounter *mount.SafeFormatAndMount,
49-
deviceUtils mountmanager.DeviceUtils, meta metadataservice.MetadataService, statter mountmanager.Statter, name, vendorVersion string) error {
48+
func (gceDriver *GCEDriver) SetupGCEDriver(name, vendorVersion string, identityServer *GCEIdentityServer, controllerServer *GCEControllerServer, nodeServer *GCENodeServer) error {
5049
if name == "" {
5150
return fmt.Errorf("Driver name missing")
5251
}
5352

54-
gceDriver.name = name
55-
gceDriver.vendorVersion = vendorVersion
56-
5753
// Adding Capabilities
5854
vcam := []csi.VolumeCapability_AccessMode_Mode{
5955
csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
@@ -78,10 +74,11 @@ func (gceDriver *GCEDriver) SetupGCEDriver(cloudProvider gce.GCECompute, mounter
7874
}
7975
gceDriver.AddNodeServiceCapabilities(ns)
8076

81-
// Set up RPC Servers
82-
gceDriver.ids = NewIdentityServer(gceDriver)
83-
gceDriver.ns = NewNodeServer(gceDriver, mounter, deviceUtils, meta, statter)
84-
gceDriver.cs = NewControllerServer(gceDriver, cloudProvider, meta)
77+
gceDriver.name = name
78+
gceDriver.vendorVersion = vendorVersion
79+
gceDriver.ids = identityServer
80+
gceDriver.cs = controllerServer
81+
gceDriver.ns = nodeServer
8582

8683
return nil
8784
}
@@ -147,12 +144,11 @@ func NewNodeServer(gceDriver *GCEDriver, mounter *mount.SafeFormatAndMount, devi
147144
}
148145
}
149146

150-
func NewControllerServer(gceDriver *GCEDriver, cloudProvider gce.GCECompute, meta metadataservice.MetadataService) *GCEControllerServer {
147+
func NewControllerServer(gceDriver *GCEDriver, cloudProvider gce.GCECompute) *GCEControllerServer {
151148
return &GCEControllerServer{
152-
Driver: gceDriver,
153-
CloudProvider: cloudProvider,
154-
MetadataService: meta,
155-
volumeLocks: common.NewVolumeLocks(),
149+
Driver: gceDriver,
150+
CloudProvider: cloudProvider,
151+
volumeLocks: common.NewVolumeLocks(),
156152
}
157153
}
158154

0 commit comments

Comments
 (0)