diff --git a/pkg/apis/ceph.rook.io/v1/cluster.go b/pkg/apis/ceph.rook.io/v1/cluster.go index 615ffc4ae..36e800e05 100644 --- a/pkg/apis/ceph.rook.io/v1/cluster.go +++ b/pkg/apis/ceph.rook.io/v1/cluster.go @@ -33,6 +33,17 @@ func (c *ClusterSpec) RequireMsgr2() bool { return false } +// RequireMsgr2 checks if the network settings require the msgr2 protocol +func (c *ClusterSpec) NetworkEncryptionEnabled() bool { + if c.Network.Connections == nil { + return false + } + if c.Network.Connections.Encryption == nil { + return false + } + return c.Network.Connections.Encryption.Enabled +} + func (c *ClusterSpec) IsStretchCluster() bool { return c.Mon.StretchCluster != nil && len(c.Mon.StretchCluster.Zones) > 0 } diff --git a/pkg/operator/ceph/cluster/cluster.go b/pkg/operator/ceph/cluster/cluster.go index bccaf9595..97d0af2c4 100755 --- a/pkg/operator/ceph/cluster/cluster.go +++ b/pkg/operator/ceph/cluster/cluster.go @@ -758,9 +758,7 @@ func (c *cluster) configureMsgr2() error { } monStore := config.GetMonStore(c.context, c.ClusterInfo) - encryptionEnabled := c.Spec.Network.Connections != nil && - c.Spec.Network.Connections.Encryption != nil && - c.Spec.Network.Connections.Encryption.Enabled + encryptionEnabled := c.Spec.NetworkEncryptionEnabled() if encryptionEnabled { logger.Infof("setting msgr2 encryption mode to %q", encryptionSetting) diff --git a/pkg/operator/ceph/controller/cluster_info.go b/pkg/operator/ceph/controller/cluster_info.go index 5f51f4b1c..bdbba4f6b 100644 --- a/pkg/operator/ceph/controller/cluster_info.go +++ b/pkg/operator/ceph/controller/cluster_info.go @@ -163,11 +163,8 @@ func CreateOrLoadClusterInfo(clusterdContext *clusterd.Context, context context. // can run on remote executor clusterInfo.NetworkSpec = cephClusterSpec.Network - // update clusterInfo with cephClusterSpec.CSI. - clusterInfo.CSIDriverSpec = cephClusterSpec.CSI - if len(clusterInfo.CSIDriverSpec.ReadAffinity.CrushLocationLabels) == 0 { - clusterInfo.CSIDriverSpec.ReadAffinity.CrushLocationLabels = strings.Split(topology.GetDefaultTopologyLabels(), ",") - } + // update clusterInfo with cephClusterSpec.CSI settings + clusterInfo.CSIDriverSpec = loadCsiSettings(cephClusterSpec) // If an admin key was provided we don't need to load the other resources // Some people might want to give the admin key @@ -191,6 +188,25 @@ func CreateOrLoadClusterInfo(clusterdContext *clusterd.Context, context context. return clusterInfo, maxMonID, monMapping, nil } +func loadCsiSettings(cephClusterSpec *cephv1.ClusterSpec) cephv1.CSIDriverSpec { + settings := cephClusterSpec.CSI + if len(settings.ReadAffinity.CrushLocationLabels) == 0 { + settings.ReadAffinity.CrushLocationLabels = strings.Split(topology.GetDefaultTopologyLabels(), ",") + } + // if the csi spec does not specify mount options, apply them from the operator env vars + if cephClusterSpec.CSI.CephFS.KernelMountOptions == "" { + settings.CephFS.KernelMountOptions = k8sutil.GetOperatorSetting("CSI_CEPHFS_KERNEL_MOUNT_OPTIONS", "") + // if the kernel mount options are not set and encryption is enabled, set the default to secure + if settings.CephFS.KernelMountOptions == "" { + if cephClusterSpec.NetworkEncryptionEnabled() { + logger.Info("setting default cephfs kernel mount options to 'ms_mode=secure' since encryption is enabled") + settings.CephFS.KernelMountOptions = "ms_mode=secure" + } + } + } + return settings +} + // create new cluster info (FSID, shared keys) func createNamedClusterInfo(context *clusterd.Context, namespace string) (*cephclient.ClusterInfo, error) { fsid, err := uuid.NewRandom() diff --git a/pkg/operator/ceph/controller/cluster_info_test.go b/pkg/operator/ceph/controller/cluster_info_test.go index d95394dac..c57b7d996 100644 --- a/pkg/operator/ceph/controller/cluster_info_test.go +++ b/pkg/operator/ceph/controller/cluster_info_test.go @@ -139,4 +139,38 @@ func TestCreateClusterSecrets(t *testing.T) { assert.NoError(t, err) assert.Equal(t, "testid", info.CephCred.Username) assert.Equal(t, "testkey", info.CephCred.Secret) + assert.Equal(t, "", info.CSIDriverSpec.CephFS.KernelMountOptions) + + // Verify the csi settings default to secure if the network is encrypted + cephClusterSpec.Network = cephv1.NetworkSpec{ + Connections: &cephv1.ConnectionsSpec{ + Encryption: &cephv1.EncryptionSpec{ + Enabled: true, + }, + }, + } + info, _, _, err = CreateOrLoadClusterInfo(context, ctx, namespace, ownerInfo, cephClusterSpec) + assert.NoError(t, err) + assert.Equal(t, "ms_mode=secure", info.CSIDriverSpec.CephFS.KernelMountOptions) + + // Verify the csi settings are loaded from an env var + cephClusterSpec.Network = cephv1.NetworkSpec{} + t.Setenv("CSI_CEPHFS_KERNEL_MOUNT_OPTIONS", "ms_mode=crc") + info, _, _, err = CreateOrLoadClusterInfo(context, ctx, namespace, ownerInfo, cephClusterSpec) + assert.NoError(t, err) + assert.Equal(t, "ms_mode=crc", info.CSIDriverSpec.CephFS.KernelMountOptions) + + // Verify the csi settings are loaded from the cephClusterSpec if specified and override the env var + cephClusterSpec.CSI = cephv1.CSIDriverSpec{ + ReadAffinity: cephv1.ReadAffinitySpec{ + Enabled: true, + CrushLocationLabels: []string{"kubernetes.io/hostname"}, + }, + CephFS: cephv1.CSICephFSSpec{ + KernelMountOptions: "ms_mode=secure", + }, + } + info, _, _, err = CreateOrLoadClusterInfo(context, ctx, namespace, ownerInfo, cephClusterSpec) + assert.NoError(t, err) + assert.Equal(t, "ms_mode=secure", info.CSIDriverSpec.CephFS.KernelMountOptions) } diff --git a/pkg/operator/ceph/csi/config.go b/pkg/operator/ceph/csi/config.go index d853d2b9b..4d1bf54af 100644 --- a/pkg/operator/ceph/csi/config.go +++ b/pkg/operator/ceph/csi/config.go @@ -55,26 +55,7 @@ func CreateUpdateClientProfileRadosNamespace(ctx context.Context, c client.Clien }, } - err := c.Get(ctx, types.NamespacedName{Name: csiOpClientProfile.Name, Namespace: csiOpClientProfile.Namespace}, csiOpClientProfile) - if err != nil { - if apierrors.IsNotFound(err) { - err = c.Create(ctx, csiOpClientProfile) - if err != nil { - return errors.Wrapf(err, "failed to create ceph-csi clientProfile cr for RBD %q", csiOpClientProfile.Name) - } - logger.Infof("successfully created ceph-csi clientProfile CR for RBD %q", csiOpClientProfile.Name) - return nil - } - return err - } - - err = c.Update(ctx, csiOpClientProfile) - if err != nil { - return errors.Wrapf(err, "failed to create ceph-csi clientProfile cr for RBD %q", csiOpClientProfile.Name) - } - logger.Infof("successfully updated ceph-csi clientProfile CR for RBD %q", csiOpClientProfile.Name) - - return nil + return createUpdateClientProfile(c, clusterInfo, csiOpClientProfile) } func CreateUpdateClientProfileSubVolumeGroup(ctx context.Context, c client.Client, clusterInfo *cephclient.ClusterInfo, cephFilesystemSubVolumeGroupName, clusterID string) error { @@ -82,26 +63,7 @@ func CreateUpdateClientProfileSubVolumeGroup(ctx context.Context, c client.Clien csiOpClientProfile := generateProfileSubVolumeGroupSpec(clusterInfo, cephFilesystemSubVolumeGroupName, clusterID) - err := c.Get(ctx, types.NamespacedName{Name: csiOpClientProfile.Name, Namespace: csiOpClientProfile.Namespace}, csiOpClientProfile) - if err != nil { - if apierrors.IsNotFound(err) { - err = c.Create(ctx, csiOpClientProfile) - if err != nil { - return errors.Wrapf(err, "failed to create ceph-csi clientProfile cr for subVolGrp %q", csiOpClientProfile.Name) - } - logger.Infof("successfully created ceph-csi clientProfile CR for subVolGrp %q", csiOpClientProfile.Name) - return nil - } - return err - } - - err = c.Update(ctx, csiOpClientProfile) - if err != nil { - return errors.Wrapf(err, "failed to create ceph-csi clientProfile cr for subVolGrp %q", csiOpClientProfile.Name) - } - logger.Infof("successfully updated ceph-csi clientProfile CR for subVolGrp %q", csiOpClientProfile.Name) - - return nil + return createUpdateClientProfile(c, clusterInfo, csiOpClientProfile) } func generateProfileSubVolumeGroupSpec(clusterInfo *cephclient.ClusterInfo, cephFilesystemSubVolumeGroupName, clusterID string) *csiopv1.ClientProfile { @@ -189,24 +151,30 @@ func CreateDefaultClientProfile(c client.Client, clusterInfo *cephclient.Cluster }, } - err := c.Get(clusterInfo.Context, types.NamespacedName{Name: csiOpClientProfile.Name, Namespace: csiOpClientProfile.Namespace}, csiOpClientProfile) + return createUpdateClientProfile(c, clusterInfo, csiOpClientProfile) +} + +func createUpdateClientProfile(c client.Client, clusterInfo *cephclient.ClusterInfo, clientProfile *csiopv1.ClientProfile) error { + existingCsiOpClientProfile := &csiopv1.ClientProfile{} + err := c.Get(clusterInfo.Context, types.NamespacedName{Name: clientProfile.Name, Namespace: clientProfile.Namespace}, existingCsiOpClientProfile) if err != nil { if apierrors.IsNotFound(err) { - err = c.Create(clusterInfo.Context, csiOpClientProfile) + err = c.Create(clusterInfo.Context, clientProfile) if err != nil { - return errors.Wrapf(err, "failed to create ceph-csi for default clientProfile CR %q", csiOpClientProfile.Name) + return errors.Wrapf(err, "failed to create ceph-csi for clientProfile CR %q", clientProfile.Name) } - logger.Infof("successfully created ceph-csi for default clientProfile CR %q", csiOpClientProfile.Name) + logger.Infof("successfully created ceph-csi for clientProfile CR %q", clientProfile.Name) return nil } return err } - err = c.Update(clusterInfo.Context, csiOpClientProfile) + existingCsiOpClientProfile.Spec = clientProfile.Spec + err = c.Update(clusterInfo.Context, existingCsiOpClientProfile) if err != nil { - return errors.Wrapf(err, "failed to create ceph-csi for default clientProfile CR %q", csiOpClientProfile.Name) + return errors.Wrapf(err, "failed to create ceph-csi for clientProfile CR %q", clientProfile.Name) } - logger.Infof("successfully updated ceph-csi for default clientProfile CR %q", csiOpClientProfile.Name) + logger.Infof("successfully updated ceph-csi for clientProfile CR %q", clientProfile.Name) return nil }