File: update.rb

package info (click to toggle)
vagrant 2.2.14%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 9,800 kB
  • sloc: ruby: 97,301; sh: 375; makefile: 16; lisp: 1
file content (176 lines) | stat: -rw-r--r-- 6,163 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
require 'optparse'

require_relative 'download_mixins'

module VagrantPlugins
  module CommandBox
    module Command
      class Update < Vagrant.plugin("2", :command)
        include DownloadMixins

        def execute
          options = {}
          download_options = {}

          opts = OptionParser.new do |o|
            o.banner = "Usage: vagrant box update [options]"
            o.separator ""
            o.separator "Updates the box that is in use in the current Vagrant environment,"
            o.separator "if there any updates available. This does not destroy/recreate the"
            o.separator "machine, so you'll have to do that to see changes."
            o.separator ""
            o.separator "To update a specific box (not tied to a Vagrant environment), use the"
            o.separator "--box flag."
            o.separator ""
            o.separator "Options:"
            o.separator ""

            o.on("--box BOX", String, "Update a specific box") do |b|
              options[:box] = b
            end

            o.on("--provider PROVIDER", String, "Update box with specific provider") do |p|
              options[:provider] = p.to_sym
            end

            o.on("-f", "--force", "Overwrite an existing box if it exists") do |f|
              options[:force] = f
            end

            build_download_options(o, download_options)
          end

          argv = parse_options(opts)
          return if !argv

          if options[:box]
            update_specific(options[:box], options[:provider], download_options, options[:force])
          else
            update_vms(argv, options[:provider], download_options, options[:force])
          end

          0
        end

        def update_specific(name, provider, download_options, force)
          boxes = {}
          @env.boxes.all.each do |n, v, p|
            boxes[n] ||= {}
            boxes[n][p] ||= []
            boxes[n][p] << v
          end

          if !boxes[name]
            raise Vagrant::Errors::BoxNotFound, name: name.to_s
          end

          if !provider
            if boxes[name].length > 1
              raise Vagrant::Errors::BoxUpdateMultiProvider,
                name: name.to_s,
                providers: boxes[name].keys.map(&:to_s).sort.join(", ")
            end

            provider = boxes[name].keys.first
          elsif !boxes[name][provider]
            raise Vagrant::Errors::BoxNotFoundWithProvider,
              name: name.to_s,
              provider: provider.to_s,
              providers: boxes[name].keys.map(&:to_s).sort.join(", ")
          end

          to_update = [
            [name, provider, boxes[name][provider].sort_by{|n| Gem::Version.new(n)}.last],
          ]

          to_update.each do |n, p, v|
            box = @env.boxes.find(n, p, v)
            box_update(box, "> #{v}", @env.ui, download_options, force)
          end
        end

        def update_vms(argv, provider, download_options, force)
          machines = {}

          with_target_vms(argv, provider: provider) do |machine|
            if !machine.config.vm.box
              machine.ui.output(I18n.t(
                "vagrant.errors.box_update_no_name"))
              next
            end

            if !machine.box
              collection = Vagrant::BoxCollection.new(@env.boxes_path)
              machine.box = collection.find(machine.config.vm.box, provider || machine.provider_name || @env.default_provider, "> 0")
              if !machine.box
                machine.ui.output(I18n.t(
                  "vagrant.errors.box_update_no_box",
                  name: machine.config.vm.box))
                next
              end
            end

            name     = machine.box.name
            provider = machine.box.provider
            version  = machine.config.vm.box_version || machine.box.version

            machines["#{name}_#{provider}_#{version}"] = machine
          end

          machines.each do |_, machine|
            box = machine.box
            version = machine.config.vm.box_version
            # Get download options from machine configuration if not specified
            # on the command line.
            download_options[:ca_cert] ||= machine.config.vm.box_download_ca_cert
            download_options[:ca_path] ||= machine.config.vm.box_download_ca_path
            download_options[:client_cert] ||= machine.config.vm.box_download_client_cert
            if download_options[:insecure].nil?
              download_options[:insecure] = machine.config.vm.box_download_insecure
            end

            begin
              box_update(box, version, machine.ui, download_options, force)
            rescue Vagrant::Errors::BoxUpdateNoMetadata => e
              machine.ui.warn(e)
              next
            end
          end
        end

        def box_update(box, version, ui, download_options, force)
          ui.output(I18n.t("vagrant.box_update_checking", name: box.name))
          ui.detail("Latest installed version: #{box.version}")
          ui.detail("Version constraints: #{version}")
          ui.detail("Provider: #{box.provider}")

          update = box.has_update?(version, download_options: download_options)
          if !update
            ui.success(I18n.t(
              "vagrant.box_up_to_date_single",
              name: box.name, version: box.version))
            return
          end

          ui.output(I18n.t(
            "vagrant.box_updating",
            name: update[0].name,
            provider: update[2].name,
            old: box.version,
            new: update[1].version))
          @env.action_runner.run(Vagrant::Action.action_box_add, {
            box_url: box.metadata_url,
            box_provider: update[2].name,
            box_version: update[1].version,
            ui: ui,
            box_force: force,
            box_download_client_cert: download_options[:client_cert],
            box_download_ca_cert: download_options[:ca_cert],
            box_download_ca_path: download_options[:ca_path],
            box_download_insecure: download_options[:insecure]
          })
        end
      end
    end
  end
end