diff --git a/internal/cephfs/util.go b/internal/cephfs/util.go index ee1920bd1..11e949b2f 100644 --- a/internal/cephfs/util.go +++ b/internal/cephfs/util.go @@ -18,130 +18,14 @@ package cephfs import ( "context" - "fmt" "time" - "github.com/ceph/ceph-csi/internal/util" "github.com/ceph/ceph-csi/internal/util/log" - "github.com/container-storage-interface/spec/lib/go/csi" "github.com/golang/protobuf/ptypes" "github.com/golang/protobuf/ptypes/timestamp" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) -type volumeID string - -func execCommandErr(ctx context.Context, program string, args ...string) error { - _, _, err := util.ExecCommand(ctx, program, args...) - - return err -} - -// Controller service request validation. -func (cs *ControllerServer) validateCreateVolumeRequest(req *csi.CreateVolumeRequest) error { - if err := cs.Driver.ValidateControllerServiceRequest( - csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME); err != nil { - return fmt.Errorf("invalid CreateVolumeRequest: %w", err) - } - - if req.GetName() == "" { - return status.Error(codes.InvalidArgument, "volume Name cannot be empty") - } - - reqCaps := req.GetVolumeCapabilities() - if reqCaps == nil { - return status.Error(codes.InvalidArgument, "volume Capabilities cannot be empty") - } - - for _, capability := range reqCaps { - if capability.GetBlock() != nil { - return status.Error(codes.Unimplemented, "block volume not supported") - } - } - - // Allow readonly access mode for volume with content source - err := util.CheckReadOnlyManyIsSupported(req) - if err != nil { - return err - } - - if req.VolumeContentSource != nil { - volumeSource := req.VolumeContentSource - switch volumeSource.Type.(type) { - case *csi.VolumeContentSource_Snapshot: - snapshot := req.VolumeContentSource.GetSnapshot() - // CSI spec requires returning NOT_FOUND when the volumeSource is missing/incorrect. - if snapshot == nil { - return status.Error(codes.NotFound, "volume Snapshot cannot be empty") - } - if snapshot.GetSnapshotId() == "" { - return status.Error(codes.NotFound, "volume Snapshot ID cannot be empty") - } - case *csi.VolumeContentSource_Volume: - // CSI spec requires returning NOT_FOUND when the volumeSource is missing/incorrect. - vol := req.VolumeContentSource.GetVolume() - if vol == nil { - return status.Error(codes.NotFound, "volume cannot be empty") - } - if vol.GetVolumeId() == "" { - return status.Error(codes.NotFound, "volume ID cannot be empty") - } - - default: - return status.Error(codes.InvalidArgument, "unsupported volume data source") - } - } - - return nil -} - -func (cs *ControllerServer) validateDeleteVolumeRequest() error { - if err := cs.Driver.ValidateControllerServiceRequest( - csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME); err != nil { - return fmt.Errorf("invalid DeleteVolumeRequest: %w", err) - } - - return nil -} - -// Controller expand volume request validation. -func (cs *ControllerServer) validateExpandVolumeRequest(req *csi.ControllerExpandVolumeRequest) error { - if err := cs.Driver.ValidateControllerServiceRequest(csi.ControllerServiceCapability_RPC_EXPAND_VOLUME); err != nil { - return fmt.Errorf("invalid ExpandVolumeRequest: %w", err) - } - - if req.GetVolumeId() == "" { - return status.Error(codes.InvalidArgument, "Volume ID cannot be empty") - } - - capRange := req.GetCapacityRange() - if capRange == nil { - return status.Error(codes.InvalidArgument, "CapacityRange cannot be empty") - } - - return nil -} - -func genSnapFromOptions(ctx context.Context, req *csi.CreateSnapshotRequest) (snap *cephfsSnapshot, err error) { - cephfsSnap := &cephfsSnapshot{} - cephfsSnap.RequestName = req.GetName() - snapOptions := req.GetParameters() - - cephfsSnap.Monitors, cephfsSnap.ClusterID, err = util.GetMonsAndClusterID(snapOptions) - if err != nil { - log.ErrorLog(ctx, "failed getting mons (%s)", err) - - return nil, err - } - if namePrefix, ok := snapOptions["snapshotNamePrefix"]; ok { - cephfsSnap.NamePrefix = namePrefix - } - - return cephfsSnap, nil -} - func parseTime(ctx context.Context, createTime time.Time) (*timestamp.Timestamp, error) { tm, err := ptypes.TimestampProto(createTime) if err != nil { diff --git a/internal/cephfs/validator.go b/internal/cephfs/validator.go new file mode 100644 index 000000000..07e38688c --- /dev/null +++ b/internal/cephfs/validator.go @@ -0,0 +1,113 @@ +/* +Copyright 2021 The Ceph-CSI Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cephfs + +import ( + "fmt" + + "github.com/ceph/ceph-csi/internal/util" + + "github.com/container-storage-interface/spec/lib/go/csi" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// validateCreateVolumeRequest validates the Controller CreateVolume request. +func (cs *ControllerServer) validateCreateVolumeRequest(req *csi.CreateVolumeRequest) error { + if err := cs.Driver.ValidateControllerServiceRequest( + csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME); err != nil { + return fmt.Errorf("invalid CreateVolumeRequest: %w", err) + } + + if req.GetName() == "" { + return status.Error(codes.InvalidArgument, "volume Name cannot be empty") + } + + reqCaps := req.GetVolumeCapabilities() + if reqCaps == nil { + return status.Error(codes.InvalidArgument, "volume Capabilities cannot be empty") + } + + for _, capability := range reqCaps { + if capability.GetBlock() != nil { + return status.Error(codes.Unimplemented, "block volume not supported") + } + } + + // Allow readonly access mode for volume with content source + err := util.CheckReadOnlyManyIsSupported(req) + if err != nil { + return err + } + + if req.VolumeContentSource != nil { + volumeSource := req.VolumeContentSource + switch volumeSource.Type.(type) { + case *csi.VolumeContentSource_Snapshot: + snapshot := req.VolumeContentSource.GetSnapshot() + // CSI spec requires returning NOT_FOUND when the volumeSource is missing/incorrect. + if snapshot == nil { + return status.Error(codes.NotFound, "volume Snapshot cannot be empty") + } + if snapshot.GetSnapshotId() == "" { + return status.Error(codes.NotFound, "volume Snapshot ID cannot be empty") + } + case *csi.VolumeContentSource_Volume: + // CSI spec requires returning NOT_FOUND when the volumeSource is missing/incorrect. + vol := req.VolumeContentSource.GetVolume() + if vol == nil { + return status.Error(codes.NotFound, "volume cannot be empty") + } + if vol.GetVolumeId() == "" { + return status.Error(codes.NotFound, "volume ID cannot be empty") + } + + default: + return status.Error(codes.InvalidArgument, "unsupported volume data source") + } + } + + return nil +} + +// validateDeleteVolumeRequest validates the Controller DeleteVolume request. +func (cs *ControllerServer) validateDeleteVolumeRequest() error { + if err := cs.Driver.ValidateControllerServiceRequest( + csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME); err != nil { + return fmt.Errorf("invalid DeleteVolumeRequest: %w", err) + } + + return nil +} + +// validateExpandVolumeRequest validates the Controller ExpandVolume request. +func (cs *ControllerServer) validateExpandVolumeRequest(req *csi.ControllerExpandVolumeRequest) error { + if err := cs.Driver.ValidateControllerServiceRequest(csi.ControllerServiceCapability_RPC_EXPAND_VOLUME); err != nil { + return fmt.Errorf("invalid ExpandVolumeRequest: %w", err) + } + + if req.GetVolumeId() == "" { + return status.Error(codes.InvalidArgument, "Volume ID cannot be empty") + } + + capRange := req.GetCapacityRange() + if capRange == nil { + return status.Error(codes.InvalidArgument, "CapacityRange cannot be empty") + } + + return nil +} diff --git a/internal/cephfs/volumemounter.go b/internal/cephfs/volumemounter.go index 04ad0f5b0..0fa4f4757 100644 --- a/internal/cephfs/volumemounter.go +++ b/internal/cephfs/volumemounter.go @@ -66,6 +66,12 @@ var ( } ) +func execCommandErr(ctx context.Context, program string, args ...string) error { + _, _, err := util.ExecCommand(ctx, program, args...) + + return err +} + // Load available ceph mounters installed on system into availableMounters // Called from driver.go's Run(). func loadAvailableMounters(conf *util.Config) error { diff --git a/internal/cephfs/volumeoptions.go b/internal/cephfs/volumeoptions.go index 3a44cae22..8600664dc 100644 --- a/internal/cephfs/volumeoptions.go +++ b/internal/cephfs/volumeoptions.go @@ -27,8 +27,11 @@ import ( cerrors "github.com/ceph/ceph-csi/internal/cephfs/errors" "github.com/ceph/ceph-csi/internal/util" + "github.com/ceph/ceph-csi/internal/util/log" ) +type volumeID string + type volumeOptions struct { TopologyPools *[]util.TopologyConstrainedPool TopologyRequirement *csi.TopologyRequirement @@ -586,3 +589,21 @@ func newSnapshotOptionsFromID( return &volOptions, &info, &sid, nil } + +func genSnapFromOptions(ctx context.Context, req *csi.CreateSnapshotRequest) (snap *cephfsSnapshot, err error) { + cephfsSnap := &cephfsSnapshot{} + cephfsSnap.RequestName = req.GetName() + snapOptions := req.GetParameters() + + cephfsSnap.Monitors, cephfsSnap.ClusterID, err = util.GetMonsAndClusterID(snapOptions) + if err != nil { + log.ErrorLog(ctx, "failed getting mons (%s)", err) + + return nil, err + } + if namePrefix, ok := snapOptions["snapshotNamePrefix"]; ok { + cephfsSnap.NamePrefix = namePrefix + } + + return cephfsSnap, nil +} diff --git a/internal/controller/persistentvolume/persistentvolume.go b/internal/controller/persistentvolume/persistentvolume.go index 0e81b58d5..269ec757c 100644 --- a/internal/controller/persistentvolume/persistentvolume.go +++ b/internal/controller/persistentvolume/persistentvolume.go @@ -19,7 +19,6 @@ import ( "context" "errors" "fmt" - "strconv" ctrl "github.com/ceph/ceph-csi/internal/controller" "github.com/ceph/ceph-csi/internal/rbd" @@ -126,19 +125,8 @@ func (r *ReconcilePersistentVolume) getCredentials( return cr, nil } -func checkStaticVolume(pv *corev1.PersistentVolume) (bool, error) { - static := false - var err error - - staticVol := pv.Spec.CSI.VolumeAttributes["staticVolume"] - if staticVol != "" { - static, err = strconv.ParseBool(staticVol) - if err != nil { - return false, fmt.Errorf("failed to parse preProvisionedVolume: %w", err) - } - } - - return static, nil +func checkStaticVolume(pv *corev1.PersistentVolume) bool { + return pv.Spec.CSI.VolumeAttributes["staticVolume"] == "true" } // storeVolumeIDInPV stores the new volumeID in PV object. @@ -178,10 +166,7 @@ func (r ReconcilePersistentVolume) reconcilePV(ctx context.Context, obj runtime. secretName := "" secretNamespace := "" // check static volume - static, err := checkStaticVolume(pv) - if err != nil { - return err - } + static := checkStaticVolume(pv) // if the volume is static, dont generate OMAP data if static { return nil diff --git a/internal/kms/vault.go b/internal/kms/vault.go index 6a7fc001c..d1e146538 100644 --- a/internal/kms/vault.go +++ b/internal/kms/vault.go @@ -192,11 +192,16 @@ func (vc *vaultConnection) initConnection(config map[string]interface{}) error { if errors.Is(err, errConfigOptionInvalid) { return err } - vaultAuthNamespace := vaultNamespace // optional, same as vaultNamespace + vaultAuthNamespace := "" err = setConfigString(&vaultAuthNamespace, config, "vaultAuthNamespace") if errors.Is(err, errConfigOptionInvalid) { return err } + // if the vaultAuthNamespace key is present and value is empty in config, set + // the optional vaultNamespace. + if vaultAuthNamespace == "" { + vaultAuthNamespace = vaultNamespace + } // set the option if the value was not invalid if firstInit || !errors.Is(err, errConfigOptionMissing) { vaultConfig[api.EnvVaultNamespace] = vaultAuthNamespace diff --git a/internal/util/conn_pool.go b/internal/util/conn_pool.go index 3987101dd..aca2bb482 100644 --- a/internal/util/conn_pool.go +++ b/internal/util/conn_pool.go @@ -145,6 +145,10 @@ func (cp *ConnPool) Get(monitors, user, keyfile string) (*rados.Conn, error) { return nil, fmt.Errorf("parsing cmdline args (%v) failed: %w", args, err) } + if err = conn.ReadConfigFile(CephConfigPath); err != nil { + return nil, fmt.Errorf("failed to read config file %q: %w", CephConfigPath, err) + } + err = conn.Connect() if err != nil { return nil, fmt.Errorf("connecting failed: %w", err)