Class: Yast2::FsSnapshot

Inherits:
Object
  • Object
show all
Includes:
Yast::Logger
Defined in:
library/system/src/lib/yast2/fs_snapshot.rb

Overview

Class for managing filesystem snapshots. It's important to note that this class is intended to be used during installation/update so it uses the Snapper's CLI because the DBus interface is not available at that time.

Constant Summary collapse

FIND_CONFIG_CMD =
"/usr/bin/snapper --no-dbus --root=%{root} --csvout list-configs " \
"--columns config,subvolume | /usr/bin/grep \"^root,\" >/dev/null".freeze
CREATE_SNAPSHOT_CMD =
"/usr/bin/snapper --no-dbus --root=%{root} create "\
"--type %{snapshot_type} --description %{description}".freeze
LIST_SNAPSHOTS_CMD =
"/usr/bin/snapper --no-dbus --root=%{root} --utc --csvout list --disable-used-space " \
"--columns number,type,pre-number,date,user,cleanup,description".freeze
CLEANUP_STRATEGY =

Predefined snapshot cleanup strategies (the user can define custom ones, too)

{ number: "number", timeline: "timeline" }.freeze

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(number, snapshot_type, previous_number, timestamp, user, cleanup_algo, description) ⇒ FsSnapshot

FsSnapshot constructor

This method is not intended to be called by users of FsSnapshot class. Instead, class methods must be used.

Parameters:

  • number (Fixnum)

    Snapshot's number.

  • snapshot_type (Symbol)

    Snapshot's type: :pre, :post or :single.

  • previous_number (Fixnum, nil)

    Previous snapshot's number; nil if the snapshot has no pre snapshot associated to it.

  • timestamp (DateTime, nil)

    Timestamp; nil if the datetime is unknown.

  • user (String, nil)

    Snapshot's owner username; nil if the owner is unknown.

  • cleanup_algo (Symbol, nil)

    Clean-up algorithm; nil if the algorithm is unknown.

  • description (String, nil)

    Snapshot's description; nil if the snapshot has no description.



105
106
107
108
109
110
111
112
113
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 105

def initialize(number, snapshot_type, previous_number, timestamp, user, cleanup_algo, description)
  @number = number
  @snapshot_type = snapshot_type
  @previous_number = previous_number
  @timestamp = timestamp
  @user = user
  @cleanup_algo = cleanup_algo
  @description = description
end

Class Attribute Details

.configure_on_install=(value) ⇒ Object (writeonly)

See Also:

  • #configure_on_install?


174
175
176
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 174

def configure_on_install=(value)
  @configure_on_install = value
end

Instance Attribute Details

#cleanup_algoObject (readonly)

Returns the value of attribute cleanup_algo.



88
89
90
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 88

def cleanup_algo
  @cleanup_algo
end

#descriptionObject (readonly)

Returns the value of attribute description.



88
89
90
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 88

def description
  @description
end

#numberObject (readonly)

Returns the value of attribute number.



88
89
90
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 88

def number
  @number
end

#previous_numberObject (readonly)

Returns the value of attribute previous_number.



88
89
90
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 88

def previous_number
  @previous_number
end

#snapshot_typeObject (readonly)

Returns the value of attribute snapshot_type.



88
89
90
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 88

def snapshot_type
  @snapshot_type
end

#timestampObject (readonly)

Returns the value of attribute timestamp.



88
89
90
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 88

def timestamp
  @timestamp
end

#userObject (readonly)

Returns the value of attribute user.



88
89
90
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 88

def user
  @user
end

Class Method Details

.allArray<FsSnapshot>

Note:

Unlike other class methods which inspect the underlying system, this method does not cache any result. It always queries snapper about existing snapshots.

Returns all snapshots

It raises an exception if Snapper is not configured.

Returns:

  • (Array<FsSnapshot>)

    All snapshots that exist in the system.

Raises:



264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 264

def all
  raise SnapperNotConfigured unless configured?

  out = Yast::SCR.Execute(
    Yast::Path.new(".target.bash_output"),
    format(LIST_SNAPSHOTS_CMD, root: target_root.shellescape)
  )

  log.info("Retrieving snapshots list: #{LIST_SNAPSHOTS_CMD} returned: #{out}")

  csv = CSV.parse(out["stdout"], headers: true, converters: [:date_time, :numeric])

  csv.each_with_object([]) do |row, snapshots|
    next if row[0] == 0 # Ignores 'current' snapshot (id = 0) because it's not a real snapshot

    fields = row.fields

    if !fields[3].is_a?(DateTime)
      log.warn("Error when parsing date/time: #{fields[3]}")
      fields[3] = nil
    end

    fields[1] = fields[1].to_sym # type
    fields[5] = fields[5].to_sym if fields[5] # cleanup

    snapshots << new(*fields)
  end
end

.configure_on_install?Boolean

Whether Snapper should be configured at the end of installation

Returns:

  • (Boolean)


169
170
171
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 169

def configure_on_install?
  !!@configure_on_install
end

.configure_snapperObject

Performs the final steps to configure snapper for the root filesystem on a fresh installation.

First part of the configuration must have been already done while the root filesystem is created.

This part here is what is left to do after the package installation in the target system is complete.

Raises:



155
156
157
158
159
160
161
162
163
164
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 155

def configure_snapper
  raise SnapperNotConfigurable if !Yast::Mode.installation || non_switched_installation?

  @configured = nil

  installation_helper_step4
  write_snapper_config
  update_etc_sysconfig_yast2
  setup_snapper_quota
end

.configured?Boolean

Determines whether snapper is configured or not

Returns:

  • (Boolean)

    true if it's configured; false otherwise.



132
133
134
135
136
137
138
139
140
141
142
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 132

def configured?
  return @configured unless @configured.nil?

  out = Yast::SCR.Execute(
    Yast::Path.new(".target.bash_output"),
    format(FIND_CONFIG_CMD, root: target_root.shellescape)
  )

  log.info("Checking if Snapper is configured: \"#{FIND_CONFIG_CMD}\" returned: #{out}")
  @configured = out["exit"] == 0
end

.create_post(description, previous_number, cleanup: nil, important: false) ⇒ FsSnapshot

Creates a new 'post' snapshot unless disabled by user

Each 'post' snapshot corresponds with a 'pre' one.

Parameters:

  • description (String)

    Snapshot's description.

  • previous_number (Fixnum)

    Number of the previous snapshot

  • cleanup (String) (defaults to: nil)

    Cleanup strategy (:number, :timeline, nil)

  • important (boolean) (defaults to: false)

    Add "important" to userdata?

Returns:

See Also:



242
243
244
245
246
247
248
249
250
251
252
253
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 242

def create_post(description, previous_number, cleanup: nil, important: false)
  return nil unless create_snapshot?(:around)

  previous = find(previous_number)

  if previous
    create(:post, description, previous: previous, cleanup: cleanup, important: important)
  else
    log.error "Previous filesystem snapshot was not found"
    raise PreviousSnapshotNotFound
  end
end

.create_pre(description, cleanup: nil, important: false) ⇒ FsSnapshot

Creates a new 'pre' snapshot

Parameters:

  • description (String)

    Snapshot's description.

Returns:

See Also:



224
225
226
227
228
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 224

def create_pre(description, cleanup: nil, important: false)
  return nil unless create_snapshot?(:around)

  create(:pre, description, cleanup: cleanup, important: important)
end

.create_single(description, cleanup: nil, important: false) ⇒ FsSnapshot

Creates a new 'single' snapshot unless disabled by user

Parameters:

  • description (String)

    Snapshot's description.

  • cleanup (String) (defaults to: nil)

    Cleanup strategy (:number, :timeline, nil)

  • important (boolean) (defaults to: false)

    Add "important" to userdata?

Returns:

See Also:



211
212
213
214
215
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 211

def create_single(description, cleanup: nil, important: false)
  return nil unless create_snapshot?(:single)

  create(:single, description, cleanup: cleanup, important: important)
end

.create_snapshot?(snapshot_type) ⇒ Boolean

Returns whether creating the given snapshot type is allowed Information is taken from Linuxrc (DISABLE_SNAPSHOTS)

  • "all" - all snapshot types are temporarily disabled
  • "around" - before and after calling YaST
  • "single" - single snapshot at a given point

Parameters:

  • one (Symbol)

    of :around (for :post and :pre snapshots) or :single

Returns:

  • (Boolean)

    if snapshot should be created



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 184

def create_snapshot?(snapshot_type)
  disable_snapshots = Yast::Linuxrc.value_for(Yast::LinuxrcClass::DISABLE_SNAPSHOTS)

  # Feature is not defined on Linuxrc commandline
  return true if disable_snapshots.nil? || disable_snapshots.empty?

  disable_snapshots = disable_snapshots.downcase.tr("-_.", "").split(",")

  if [:around, :single].include?(snapshot_type)
    return false if disable_snapshots.include?("all")

    !disable_snapshots.include?(snapshot_type.to_s)
  else
    raise ArgumentError, "Unsupported snapshot type #{snapshot_type.inspect}, " \
                         "supported are :around and :single"
  end
end

.find(number) ⇒ FsSnapshot?

Finds a snapshot by its number

It raises an exception if Snapper is not configured.

Parameters:

  • nubmer (Fixnum)

    Number of the snapshot to search for.

Returns:

  • (FsSnapshot, nil)

    The snapshot with the number +number+ if found. Otherwise, it returns nil.

See Also:



301
302
303
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 301

def find(number)
  all.find { |s| s.number == number }
end

Instance Method Details

#previousFsSnapshot?

Returns the previous snapshot

Returns:

  • (FsSnapshot, nil)

    Object representing the previous snapshot.



120
121
122
# File 'library/system/src/lib/yast2/fs_snapshot.rb', line 120

def previous
  @previous ||= @previous_number ? FsSnapshot.find(@previous_number) : nil
end