Class: OsUp::Migrator

Inherits:
Object
  • Object
show all
Defined in:
lib/osup/migrator.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pool_migrations, queue) ⇒ Migrator

Returns a new instance of Migrator.

Parameters:



144
145
146
147
# File 'lib/osup/migrator.rb', line 144

def initialize(pool_migrations, queue)
  @pool_migrations = pool_migrations
  @queue = queue
end

Instance Attribute Details

#pool_migrationsObject (readonly, protected)

Returns the value of attribute pool_migrations.



164
165
166
# File 'lib/osup/migrator.rb', line 164

def pool_migrations
  @pool_migrations
end

#queueObject (readonly, protected)

Returns the value of attribute queue.



164
165
166
# File 'lib/osup/migrator.rb', line 164

def queue
  @queue
end

Class Method Details

.rollback(pool_migrations, **opts) ⇒ Object

Parameters:

Options Hash (**opts):

  • :to (Integer)

    target migration id

  • :dry_run (Boolean)


127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/osup/migrator.rb', line 127

def self.rollback(pool_migrations, **opts)
  mapped = rollback_sequence(pool_migrations, **opts)

  if opts[:dry_run]
    mapped.each do |m|
      puts "> would down #{m.id}"
    end

    return
  end

  migrator = new(pool_migrations, mapped)
  migrator.run(:down)
end

.rollback_sequence(pool_migrations, **opts) ⇒ Array<Migration>

Prepare a list of migrations to be run for rollback

Parameters:

Options Hash (**opts):

  • :to (Integer)

    target migration id

Returns:

  • (Array<Migration>)

    ordered list of migrations to down



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/osup/migrator.rb', line 72

def self.rollback_sequence(pool_migrations, **opts)
  available = pool_migrations.all

  # Find the last applied migration
  i = available.rindex do |id, m|
    if m.nil?
      raise "unable to rollback pool #{pool_migrations.pool}: " \
            "unrecognized migration #{id}"
    end

    pool_migrations.applied?(m)
  end

  if i.nil?
    raise "unable to rollback pool #{pool_migrations.pool}: " \
          'no applied migration found'
  end

  # List of applied migrations
  applied = available[0..i].reverse

  if opts[:to]
    # Find the target version
    j = applied.index do |id, m|
      if m.nil?
        raise "unable to rollback pool #{pool_migrations.pool}: " \
              "unrecognized migration #{id}"
      end

      id == opts[:to]
    end

    if j.nil?
      raise "unable to rollback pool #{pool_migrations.pool}: " \
            "migration #{opts[:to]} not found or reacheable"

    elsif j == 0
      raise "unable to rollback pool #{pool_migrations.pool}: " \
            "would rollback migration #{id}, but it is set as the target"
    end

    list = applied[0..j - 1]

  else
    list = [applied.first]
  end

  # Convert to a list of migrations
  list.map { |_id, m| m }
end

.upgrade(pool_migrations, **opts) ⇒ Object

Parameters:

Options Hash (**opts):

  • :to (Integer)

    target migration id

  • :dry_run (Boolean)


52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/osup/migrator.rb', line 52

def self.upgrade(pool_migrations, **opts)
  mapped = upgrade_sequence(pool_migrations, **opts)

  if opts[:dry_run]
    mapped.each do |m|
      puts "> would up #{m.id}"
    end

    return
  end

  migrator = new(pool_migrations, mapped)
  migrator.run(:up)
end

.upgrade_sequence(pool_migrations, **opts) ⇒ Array<Migration>

Prepare a list of migrations to be run for upgrade

Parameters:

Options Hash (**opts):

  • :to (Integer)

    target migration id

Returns:

  • (Array<Migration>)

    ordered list of migrations to up



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/osup/migrator.rb', line 8

def self.upgrade_sequence(pool_migrations, **opts)
  available = pool_migrations.all

  # Find the last applied migration
  i = available.index do |id, m|
    if m.nil?
      raise "unable to upgrade pool #{pool_migrations.pool}: " \
            "unrecognized migration #{id}"
    end

    !pool_migrations.applied?(m)
  end

  # List of migrations to apply
  list = available[i..]

  # Check that the list is clean
  list.each do |id, m|
    if m.nil?
      raise "unable to upgrade pool #{pool_migrations.pool}: " \
            "unrecognized migration #{id}"
    end
  end

  # Verify that target version is reachable
  if opts[:to]
    j = list.index { |id, _m| id == opts[:to] }

    if j.nil?
      raise "unable to upgrade pool #{pool_migrations.pool}: " \
            "target migration #{opts[:to]} not found or reachable"
    end

    list = list[0..j]
  end

  # Convert to a list of migrations
  list.map { |_id, m| m }
end

Instance Method Details

#run(action) ⇒ Object

Parameters:

  • action (:up, :down)


150
151
152
153
154
155
156
157
158
159
160
# File 'lib/osup/migrator.rb', line 150

def run(action)
  queue.each do |m|
    puts "> #{action} #{m.id} - #{m.name}"

    raise "migration #{m.id} returned non-zero exit status" unless run_migration(m, action)

    pool_migrations.send("set_#{action}", m)
  end

  true
end

#run_migration(m, action) ⇒ Object (protected)



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/osup/migrator.rb', line 166

def run_migration(m, action)
  state = SystemState.create(
    pool_migrations.dataset,
    "#{m.id}-#{action}",
    snapshot: m.snapshot
  )

  pid = Process.fork do
    ENV.keep_if do |k, _v|
      %w[GLI_DEBUG HOME LANG LOGNAME PATH PWD USER].include?(k)
    end

    # osup is intentionally run from /run/current-system, as we don't want
    # to call it from within the osctld or any other gem bundle. osup needs
    # to be independent, so that it's environment and dependencies are clear.
    Process.exec(
      '/run/current-system/sw/bin/osup', 'run',
      pool_migrations.pool, pool_migrations.dataset, m.dirname, action.to_s
    )
  end

  Process.wait(pid)

  if $?.exitstatus == 0
    state.commit
    true
  else
    state.rollback
    false
  end
end