Skip to content

Commit

Permalink
Add a global freeze setting and volume freeze field
Browse files Browse the repository at this point in the history
* Bump longhorn-instance-manager for fsfreeze functionality
* Add a global freeze setting and volume freeze field

Longhorn 2187

Signed-off-by: Eric Weber <eric.weber@suse.com>
  • Loading branch information
ejweber authored Jun 6, 2024
1 parent 2cefc95 commit 447b80b
Show file tree
Hide file tree
Showing 29 changed files with 299 additions and 48 deletions.
57 changes: 35 additions & 22 deletions api/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type Volume struct {
OfflineReplicaRebuildingRequired bool `json:"offlineReplicaRebuildingRequired"`
SnapshotMaxCount int `json:"snapshotMaxCount"`
SnapshotMaxSize string `json:"snapshotMaxSize"`
FreezeFilesystemForSnapshot longhorn.FreezeFilesystemForSnapshot `json:"freezeFilesystemForSnapshot"`

DiskSelector []string `json:"diskSelector"`
NodeSelector []string `json:"nodeSelector"`
Expand Down Expand Up @@ -371,6 +372,10 @@ type UpdateSnapshotMaxSize struct {
SnapshotMaxSize string `json:"snapshotMaxSize"`
}

type UpdateFreezeFilesystemForSnapshotInput struct {
FreezeFilesystemForSnapshot string `json:"freezeFilesystemForSnapshot"`
}

type PVCreateInput struct {
PVName string `json:"pvName"`
FSType string `json:"fsType"`
Expand Down Expand Up @@ -629,6 +634,7 @@ func NewSchema() *client.Schemas {
schemas.AddType("UpdateReplicaSoftAntiAffinityInput", UpdateReplicaSoftAntiAffinityInput{})
schemas.AddType("UpdateReplicaZoneSoftAntiAffinityInput", UpdateReplicaZoneSoftAntiAffinityInput{})
schemas.AddType("UpdateReplicaDiskSoftAntiAffinityInput", UpdateReplicaDiskSoftAntiAffinityInput{})
schemas.AddType("UpdateFreezeFilesystemForSnapshotInput", UpdateFreezeFilesystemForSnapshotInput{})
schemas.AddType("workloadStatus", longhorn.WorkloadStatus{})
schemas.AddType("cloneStatus", longhorn.VolumeCloneStatus{})
schemas.AddType("empty", Empty{})
Expand Down Expand Up @@ -1031,6 +1037,10 @@ func volumeSchema(volume *client.Schema) {
Input: "UpdateReplicaDiskSoftAntiAffinityInput",
},

"updateFreezeFilesystemForSnapshot": {
Input: "UpdateFreezeFilesystemForSnapshotInput",
},

"pvCreate": {
Input: "PVCreateInput",
Output: "volume",
Expand Down Expand Up @@ -1508,28 +1518,29 @@ func toVolumeResource(v *longhorn.Volume, ves []*longhorn.Engine, vrs []*longhor
Actions: map[string]string{},
Links: map[string]string{},
},
Name: v.Name,
Size: strconv.FormatInt(v.Spec.Size, 10),
Frontend: v.Spec.Frontend,
DisableFrontend: v.Spec.DisableFrontend,
LastAttachedBy: v.Spec.LastAttachedBy,
FromBackup: v.Spec.FromBackup,
DataSource: v.Spec.DataSource,
NumberOfReplicas: v.Spec.NumberOfReplicas,
ReplicaAutoBalance: v.Spec.ReplicaAutoBalance,
DataLocality: v.Spec.DataLocality,
SnapshotDataIntegrity: v.Spec.SnapshotDataIntegrity,
SnapshotMaxCount: v.Spec.SnapshotMaxCount,
SnapshotMaxSize: strconv.FormatInt(v.Spec.SnapshotMaxSize, 10),
BackupCompressionMethod: v.Spec.BackupCompressionMethod,
StaleReplicaTimeout: v.Spec.StaleReplicaTimeout,
Created: v.CreationTimestamp.String(),
Image: v.Spec.Image,
BackingImage: v.Spec.BackingImage,
Standby: v.Spec.Standby,
DiskSelector: v.Spec.DiskSelector,
NodeSelector: v.Spec.NodeSelector,
RestoreVolumeRecurringJob: v.Spec.RestoreVolumeRecurringJob,
Name: v.Name,
Size: strconv.FormatInt(v.Spec.Size, 10),
Frontend: v.Spec.Frontend,
DisableFrontend: v.Spec.DisableFrontend,
LastAttachedBy: v.Spec.LastAttachedBy,
FromBackup: v.Spec.FromBackup,
DataSource: v.Spec.DataSource,
NumberOfReplicas: v.Spec.NumberOfReplicas,
ReplicaAutoBalance: v.Spec.ReplicaAutoBalance,
DataLocality: v.Spec.DataLocality,
SnapshotDataIntegrity: v.Spec.SnapshotDataIntegrity,
SnapshotMaxCount: v.Spec.SnapshotMaxCount,
SnapshotMaxSize: strconv.FormatInt(v.Spec.SnapshotMaxSize, 10),
BackupCompressionMethod: v.Spec.BackupCompressionMethod,
StaleReplicaTimeout: v.Spec.StaleReplicaTimeout,
Created: v.CreationTimestamp.String(),
Image: v.Spec.Image,
BackingImage: v.Spec.BackingImage,
Standby: v.Spec.Standby,
DiskSelector: v.Spec.DiskSelector,
NodeSelector: v.Spec.NodeSelector,
RestoreVolumeRecurringJob: v.Spec.RestoreVolumeRecurringJob,
FreezeFilesystemForSnapshot: v.Spec.FreezeFilesystemForSnapshot,

State: v.Status.State,
Robustness: v.Status.Robustness,
Expand Down Expand Up @@ -1607,6 +1618,7 @@ func toVolumeResource(v *longhorn.Volume, ves []*longhorn.Engine, vrs []*longhor
actions["updateReplicaSoftAntiAffinity"] = struct{}{}
actions["updateReplicaZoneSoftAntiAffinity"] = struct{}{}
actions["updateReplicaDiskSoftAntiAffinity"] = struct{}{}
actions["updateFreezeFilesystemForSnapshot"] = struct{}{}
actions["recurringJobAdd"] = struct{}{}
actions["recurringJobDelete"] = struct{}{}
actions["recurringJobList"] = struct{}{}
Expand Down Expand Up @@ -1638,6 +1650,7 @@ func toVolumeResource(v *longhorn.Volume, ves []*longhorn.Engine, vrs []*longhor
actions["updateReplicaSoftAntiAffinity"] = struct{}{}
actions["updateReplicaZoneSoftAntiAffinity"] = struct{}{}
actions["updateReplicaDiskSoftAntiAffinity"] = struct{}{}
actions["updateFreezeFilesystemForSnapshot"] = struct{}{}
actions["pvCreate"] = struct{}{}
actions["pvcCreate"] = struct{}{}
actions["cancelExpansion"] = struct{}{}
Expand Down
13 changes: 7 additions & 6 deletions api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,13 @@ func NewRouter(s *Server) *mux.Router {
"expand": s.VolumeExpand,
"cancelExpansion": s.VolumeCancelExpansion,

"updateReplicaCount": s.VolumeUpdateReplicaCount,
"updateReplicaAutoBalance": s.VolumeUpdateReplicaAutoBalance,
"updateSnapshotDataIntegrity": s.VolumeUpdateSnapshotDataIntegrity,
"updateBackupCompressionMethod": s.VolumeUpdateBackupCompressionMethod,
"updateOfflineReplicaRebuilding": s.VolumeUpdateOfflineReplicaRebuilding,
"replicaRemove": s.ReplicaRemove,
"updateReplicaCount": s.VolumeUpdateReplicaCount,
"updateReplicaAutoBalance": s.VolumeUpdateReplicaAutoBalance,
"updateSnapshotDataIntegrity": s.VolumeUpdateSnapshotDataIntegrity,
"updateBackupCompressionMethod": s.VolumeUpdateBackupCompressionMethod,
"updateOfflineReplicaRebuilding": s.VolumeUpdateOfflineReplicaRebuilding,
"updateFreezeFilesystemForSnapshot": s.VolumeUpdateFreezeFilesystemForSnapshot,
"replicaRemove": s.ReplicaRemove,

"engineUpgrade": s.EngineUpgrade,

Expand Down
23 changes: 23 additions & 0 deletions api/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ func (s *Server) VolumeCreate(rw http.ResponseWriter, req *http.Request) error {
ReplicaDiskSoftAntiAffinity: volume.ReplicaDiskSoftAntiAffinity,
DataEngine: volume.DataEngine,
OfflineReplicaRebuilding: volume.OfflineReplicaRebuilding,
FreezeFilesystemForSnapshot: volume.FreezeFilesystemForSnapshot,
}, volume.RecurringJobSelector)
if err != nil {
return errors.Wrap(err, "failed to create volume")
Expand Down Expand Up @@ -835,3 +836,25 @@ func (s *Server) VolumeUpdateSnapshotMaxSize(rw http.ResponseWriter, req *http.R
}
return s.responseWithVolume(rw, req, "", v)
}

func (s *Server) VolumeUpdateFreezeFilesystemForSnapshot(rw http.ResponseWriter, req *http.Request) error {
var input UpdateFreezeFilesystemForSnapshotInput
id := mux.Vars(req)["name"]

apiContext := api.GetApiContext(req)
if err := apiContext.Read(&input); err != nil {
return errors.Wrap(err, "failed to read FreezeFilesystemForSnapshot input")
}

obj, err := util.RetryOnConflictCause(func() (interface{}, error) {
return s.m.UpdateFreezeFilesystemForSnapshot(id, longhorn.FreezeFilesystemForSnapshot(input.FreezeFilesystemForSnapshot))
})
if err != nil {
return err
}
v, ok := obj.(*longhorn.Volume)
if !ok {
return fmt.Errorf("failed to convert to volume %v object", id)
}
return s.responseWithVolume(rw, req, "", v)
}
2 changes: 1 addition & 1 deletion client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ GO111MODULE=off go get
5. Generate code.

```bash
scripts/generate-longhorn-schemas.sh http://<ip>:<port>
GO111MODULE=off scripts/generate-longhorn-schemas.sh http://<ip>:<port>
```

## Copy code to longhorn-manager
Expand Down
6 changes: 4 additions & 2 deletions client/generated_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type RancherClient struct {
UpdateReplicaSoftAntiAffinityInput UpdateReplicaSoftAntiAffinityInputOperations
UpdateReplicaZoneSoftAntiAffinityInput UpdateReplicaZoneSoftAntiAffinityInputOperations
UpdateReplicaDiskSoftAntiAffinityInput UpdateReplicaDiskSoftAntiAffinityInputOperations
UpdateFreezeFSForSnapshotInput UpdateFreezeFSForSnapshotInputOperations
WorkloadStatus WorkloadStatusOperations
CloneStatus CloneStatusOperations
Empty EmptyOperations
Expand All @@ -62,11 +63,11 @@ type RancherClient struct {
Snapshot SnapshotOperations
SnapshotCR SnapshotCROperations
BackupVolume BackupVolumeOperations
BackupBackingImage BackupBackingImageOperations
Setting SettingOperations
RecurringJob RecurringJobOperations
EngineImage EngineImageOperations
BackingImage BackingImageOperations
BackupBackingImage BackupBackingImageOperations
Node NodeOperations
DiskUpdateInput DiskUpdateInputOperations
DiskInfo DiskInfoOperations
Expand Down Expand Up @@ -118,6 +119,7 @@ func constructClient(rancherBaseClient *RancherBaseClientImpl) *RancherClient {
client.UpdateReplicaSoftAntiAffinityInput = newUpdateReplicaSoftAntiAffinityInputClient(client)
client.UpdateReplicaZoneSoftAntiAffinityInput = newUpdateReplicaZoneSoftAntiAffinityInputClient(client)
client.UpdateReplicaDiskSoftAntiAffinityInput = newUpdateReplicaDiskSoftAntiAffinityInputClient(client)
client.UpdateFreezeFSForSnapshotInput = newUpdateFreezeFSForSnapshotInputClient(client)
client.WorkloadStatus = newWorkloadStatusClient(client)
client.CloneStatus = newCloneStatusClient(client)
client.Empty = newEmptyClient(client)
Expand All @@ -142,6 +144,7 @@ func constructClient(rancherBaseClient *RancherBaseClientImpl) *RancherClient {
client.Snapshot = newSnapshotClient(client)
client.SnapshotCR = newSnapshotCRClient(client)
client.BackupVolume = newBackupVolumeClient(client)
client.BackupBackingImage = newBackupBackingImageClient(client)
client.Setting = newSettingClient(client)
client.RecurringJob = newRecurringJobClient(client)
client.EngineImage = newEngineImageClient(client)
Expand All @@ -155,7 +158,6 @@ func constructClient(rancherBaseClient *RancherBaseClientImpl) *RancherClient {
client.SystemBackup = newSystemBackupClient(client)
client.SystemRestore = newSystemRestoreClient(client)
client.SnapshotCRListOutput = newSnapshotCRListOutputClient(client)
client.BackupBackingImage = newBackupBackingImageClient(client)

return client
}
Expand Down
79 changes: 79 additions & 0 deletions client/generated_update_freeze_fsfor_snapshot_input.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package client

const (
UPDATE_FREEZE_FSFOR_SNAPSHOT_INPUT_TYPE = "UpdateFreezeFSForSnapshotInput"
)

type UpdateFreezeFSForSnapshotInput struct {
Resource `yaml:"-"`

FreezeFSForSnapshot string `json:"freezeFSForSnapshot,omitempty" yaml:"freeze_fsfor_snapshot,omitempty"`
}

type UpdateFreezeFSForSnapshotInputCollection struct {
Collection
Data []UpdateFreezeFSForSnapshotInput `json:"data,omitempty"`
client *UpdateFreezeFSForSnapshotInputClient
}

type UpdateFreezeFSForSnapshotInputClient struct {
rancherClient *RancherClient
}

type UpdateFreezeFSForSnapshotInputOperations interface {
List(opts *ListOpts) (*UpdateFreezeFSForSnapshotInputCollection, error)
Create(opts *UpdateFreezeFSForSnapshotInput) (*UpdateFreezeFSForSnapshotInput, error)
Update(existing *UpdateFreezeFSForSnapshotInput, updates interface{}) (*UpdateFreezeFSForSnapshotInput, error)
ById(id string) (*UpdateFreezeFSForSnapshotInput, error)
Delete(container *UpdateFreezeFSForSnapshotInput) error
}

func newUpdateFreezeFSForSnapshotInputClient(rancherClient *RancherClient) *UpdateFreezeFSForSnapshotInputClient {
return &UpdateFreezeFSForSnapshotInputClient{
rancherClient: rancherClient,
}
}

func (c *UpdateFreezeFSForSnapshotInputClient) Create(container *UpdateFreezeFSForSnapshotInput) (*UpdateFreezeFSForSnapshotInput, error) {
resp := &UpdateFreezeFSForSnapshotInput{}
err := c.rancherClient.doCreate(UPDATE_FREEZE_FSFOR_SNAPSHOT_INPUT_TYPE, container, resp)
return resp, err
}

func (c *UpdateFreezeFSForSnapshotInputClient) Update(existing *UpdateFreezeFSForSnapshotInput, updates interface{}) (*UpdateFreezeFSForSnapshotInput, error) {
resp := &UpdateFreezeFSForSnapshotInput{}
err := c.rancherClient.doUpdate(UPDATE_FREEZE_FSFOR_SNAPSHOT_INPUT_TYPE, &existing.Resource, updates, resp)
return resp, err
}

func (c *UpdateFreezeFSForSnapshotInputClient) List(opts *ListOpts) (*UpdateFreezeFSForSnapshotInputCollection, error) {
resp := &UpdateFreezeFSForSnapshotInputCollection{}
err := c.rancherClient.doList(UPDATE_FREEZE_FSFOR_SNAPSHOT_INPUT_TYPE, opts, resp)
resp.client = c
return resp, err
}

func (cc *UpdateFreezeFSForSnapshotInputCollection) Next() (*UpdateFreezeFSForSnapshotInputCollection, error) {
if cc != nil && cc.Pagination != nil && cc.Pagination.Next != "" {
resp := &UpdateFreezeFSForSnapshotInputCollection{}
err := cc.client.rancherClient.doNext(cc.Pagination.Next, resp)
resp.client = cc.client
return resp, err
}
return nil, nil
}

func (c *UpdateFreezeFSForSnapshotInputClient) ById(id string) (*UpdateFreezeFSForSnapshotInput, error) {
resp := &UpdateFreezeFSForSnapshotInput{}
err := c.rancherClient.doById(UPDATE_FREEZE_FSFOR_SNAPSHOT_INPUT_TYPE, id, resp)
if apiError, ok := err.(*ApiError); ok {
if apiError.StatusCode == 404 {
return nil, nil
}
}
return resp, err
}

func (c *UpdateFreezeFSForSnapshotInputClient) Delete(container *UpdateFreezeFSForSnapshotInput) error {
return c.rancherClient.doResourceDelete(UPDATE_FREEZE_FSFOR_SNAPSHOT_INPUT_TYPE, &container.Resource)
}
2 changes: 2 additions & 0 deletions client/generated_volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ type Volume struct {

Encrypted bool `json:"encrypted,omitempty" yaml:"encrypted,omitempty"`

FreezeFilesystemForSnapshot string `json:"freezeFSForSnapshot,omitempty" yaml:"freeze_fsfor_snapshot,omitempty"`

FromBackup string `json:"fromBackup,omitempty" yaml:"from_backup,omitempty"`

Frontend string `json:"frontend,omitempty" yaml:"frontend,omitempty"`
Expand Down
7 changes: 6 additions & 1 deletion controller/backing_image_data_source_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -836,14 +836,19 @@ func (c *BackingImageDataSourceController) prepareRunningParameters(bids *longho
}
}
if newSnapshotRequired {
freezeFilesystem, err := c.ds.GetFreezeFilesystemForSnapshotSetting(e)
if err != nil {
return err
}

engineClientProxy, err := c.getEngineClientProxy(e)
if err != nil {
return err
}
defer engineClientProxy.Close()

snapLabels := map[string]string{types.GetLonghornLabelKey(types.LonghornLabelSnapshotForExportingBackingImage): bids.Name}
snapshotName, err := engineClientProxy.SnapshotCreate(e, bids.Name+"-"+util.RandomID(), snapLabels)
snapshotName, err := engineClientProxy.SnapshotCreate(e, bids.Name+"-"+util.RandomID(), snapLabels, freezeFilesystem)
if err != nil {
return err
}
Expand Down
6 changes: 6 additions & 0 deletions controller/setting_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1502,6 +1502,7 @@ const (
ClusterInfoVolumeRestoreVolumeRecurringJobCountFmt = "LonghornVolumeRestoreVolumeRecurringJob%sCount"
ClusterInfoVolumeSnapshotDataIntegrityCountFmt = "LonghornVolumeSnapshotDataIntegrity%sCount"
ClusterInfoVolumeUnmapMarkSnapChainRemovedCountFmt = "LonghornVolumeUnmapMarkSnapChainRemoved%sCount"
ClusterInfoVolumeFreezeFilesystemForSnapshotCountFmt = "LonghornVolumeFreezeFilesystemForSnapshot%sCount"
)

// Node Scope Info: will be sent from all Longhorn cluster nodes
Expand Down Expand Up @@ -1789,6 +1790,7 @@ func (info *ClusterInfo) collectVolumesInfo() error {
restoreVolumeRecurringJobCountStruct := newStruct()
snapshotDataIntegrityCountStruct := newStruct()
unmapMarkSnapChainRemovedCountStruct := newStruct()
freezeFilesystemForSnapshotCountStruct := newStruct()
for _, volume := range volumesRO {
dataEngine := types.ValueUnknown
if volume.Spec.DataEngine != "" {
Expand Down Expand Up @@ -1845,6 +1847,9 @@ func (info *ClusterInfo) collectVolumesInfo() error {

unmapMarkSnapChainRemoved := info.collectSettingInVolume(string(volume.Spec.UnmapMarkSnapChainRemoved), string(longhorn.UnmapMarkSnapChainRemovedIgnored), types.SettingNameRemoveSnapshotsDuringFilesystemTrim)
unmapMarkSnapChainRemovedCountStruct[util.StructName(fmt.Sprintf(ClusterInfoVolumeUnmapMarkSnapChainRemovedCountFmt, util.ConvertToCamel(string(unmapMarkSnapChainRemoved), "-")))]++

freezeFilesystemForSnapshot := info.collectSettingInVolume(string(volume.Spec.FreezeFilesystemForSnapshot), string(longhorn.FreezeFilesystemForSnapshotDefault), types.SettingNameFreezeFilesystemForSnapshot)
freezeFilesystemForSnapshotCountStruct[util.StructName(fmt.Sprintf(ClusterInfoVolumeFreezeFilesystemForSnapshotCountFmt, util.ConvertToCamel(string(freezeFilesystemForSnapshot), "-")))]++
}
info.structFields.fields.AppendCounted(accessModeCountStruct)
info.structFields.fields.AppendCounted(dataEngineCountStruct)
Expand All @@ -1858,6 +1863,7 @@ func (info *ClusterInfo) collectVolumesInfo() error {
info.structFields.fields.AppendCounted(restoreVolumeRecurringJobCountStruct)
info.structFields.fields.AppendCounted(snapshotDataIntegrityCountStruct)
info.structFields.fields.AppendCounted(unmapMarkSnapChainRemovedCountStruct)
info.structFields.fields.AppendCounted(freezeFilesystemForSnapshotCountStruct)

// TODO: Use the total volume count instead when v2 volume actual size is implemented.
// https://github.com/longhorn/longhorn/issues/5947
Expand Down
7 changes: 6 additions & 1 deletion controller/snapshot_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,11 @@ func (sc *SnapshotController) getTheOnlyEngineCRforSnapshotRO(snapshot *longhorn
}

func (sc *SnapshotController) handleSnapshotCreate(snapshot *longhorn.Snapshot, engine *longhorn.Engine) error {
freezeFilesystem, err := sc.ds.GetFreezeFilesystemForSnapshotSetting(engine)
if err != nil {
return err
}

engineCliClient, err := GetBinaryClientForEngine(engine, sc.engineClientCollection, engine.Status.CurrentImage)
if err != nil {
return err
Expand All @@ -645,7 +650,7 @@ func (sc *SnapshotController) handleSnapshotCreate(snapshot *longhorn.Snapshot,
}
if snapshotInfo == nil {
sc.logger.Infof("Creating snapshot %v of volume %v", snapshot.Name, snapshot.Spec.Volume)
_, err = engineClientProxy.SnapshotCreate(engine, snapshot.Name, snapshot.Spec.Labels)
_, err = engineClientProxy.SnapshotCreate(engine, snapshot.Name, snapshot.Spec.Labels, freezeFilesystem)
if err != nil {
return err
}
Expand Down
7 changes: 6 additions & 1 deletion controller/volume_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -4410,6 +4410,11 @@ func (c *VolumeController) createSnapshot(snapshotName string, labels map[string
return nil, err
}

freezeFilesystem, err := c.ds.GetFreezeFilesystemForSnapshotSetting(e)
if err != nil {
return nil, err
}

engineCliClient, err := engineapi.GetEngineBinaryClient(c.ds, volume.Name, c.controllerID)
if err != nil {
return nil, err
Expand All @@ -4434,7 +4439,7 @@ func (c *VolumeController) createSnapshot(snapshotName string, labels map[string
}
}

snapshotName, err = engineClientProxy.SnapshotCreate(e, snapshotName, labels)
snapshotName, err = engineClientProxy.SnapshotCreate(e, snapshotName, labels, freezeFilesystem)
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 447b80b

Please sign in to comment.