vagrant-xenserver 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +14 -0
- data/LICENSE +8 -0
- data/README.md +251 -0
- data/Rakefile +14 -0
- data/example_box/metadata.json +3 -0
- data/lib/vagrant-xenserver.rb +17 -0
- data/lib/vagrant-xenserver/action.rb +130 -0
- data/lib/vagrant-xenserver/action/clone_disk.rb +30 -0
- data/lib/vagrant-xenserver/action/connect_xs.rb +34 -0
- data/lib/vagrant-xenserver/action/create_vm.rb +83 -0
- data/lib/vagrant-xenserver/action/destroy_vm.rb +34 -0
- data/lib/vagrant-xenserver/action/dummy.rb +16 -0
- data/lib/vagrant-xenserver/action/is_created.rb +20 -0
- data/lib/vagrant-xenserver/action/is_running.rb +20 -0
- data/lib/vagrant-xenserver/action/maybe_upload_disk.rb +84 -0
- data/lib/vagrant-xenserver/action/read_ssh_info.rb +61 -0
- data/lib/vagrant-xenserver/action/read_state.rb +35 -0
- data/lib/vagrant-xenserver/action/start_vm.rb +26 -0
- data/lib/vagrant-xenserver/action/upload_vhd.rb +135 -0
- data/lib/vagrant-xenserver/action/upload_xva.rb +84 -0
- data/lib/vagrant-xenserver/config.rb +57 -0
- data/lib/vagrant-xenserver/errors.rb +29 -0
- data/lib/vagrant-xenserver/plugin.rb +29 -0
- data/lib/vagrant-xenserver/provider.rb +36 -0
- data/lib/vagrant-xenserver/util/uploader.rb +215 -0
- data/lib/vagrant-xenserver/version.rb +6 -0
- data/locales/en.yml +10 -0
- data/test +0 -0
- data/vagrant-xenserver.gemspec +22 -0
- metadata +87 -0
@@ -0,0 +1,135 @@
|
|
1
|
+
require "log4r"
|
2
|
+
require "xmlrpc/client"
|
3
|
+
require "vagrant-xenserver/util/uploader"
|
4
|
+
require "rexml/document"
|
5
|
+
require "json"
|
6
|
+
|
7
|
+
module VagrantPlugins
|
8
|
+
module XenServer
|
9
|
+
module Action
|
10
|
+
class UploadVHD
|
11
|
+
def initialize(app, env)
|
12
|
+
@app = app
|
13
|
+
@logger = Log4r::Logger.new("vagrant::xenserver::actions::upload_xva")
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
box_vhd_file = env[:machine].box.directory.join('box.vhd').to_s
|
18
|
+
|
19
|
+
hostname = env[:machine].provider_config.xs_host
|
20
|
+
session = env[:session]
|
21
|
+
|
22
|
+
@logger.info("box name=" + env[:machine].box.name.to_s)
|
23
|
+
@logger.info("box version=" + env[:machine].box.version.to_s)
|
24
|
+
|
25
|
+
# Find out if it has already been uploaded
|
26
|
+
vdis = env[:xc].call("VDI.get_all_records", env[:session])['Value']
|
27
|
+
|
28
|
+
vdi_tag = "vagrant:" + env[:machine].box.name.to_s + "/" + env[:machine].box.version.to_s
|
29
|
+
|
30
|
+
vdi_ref_rec = vdis.find { |reference,record|
|
31
|
+
@logger.info(record['tags'].to_s)
|
32
|
+
record['tags'].include?(vdi_tag)
|
33
|
+
}
|
34
|
+
|
35
|
+
if not vdi_ref_rec
|
36
|
+
|
37
|
+
# Find out virtual size of the VHD
|
38
|
+
disk_info=JSON.parse(IO.popen(["qemu-img", "info",box_vhd_file,"--output=json"]).read)
|
39
|
+
virtual_size = disk_info['virtual-size']
|
40
|
+
|
41
|
+
pool=env[:xc].call("pool.get_all",env[:session])['Value'][0]
|
42
|
+
default_sr=env[:xc].call("pool.get_default_SR",env[:session],pool)['Value']
|
43
|
+
@logger.info("default_SR="+default_sr)
|
44
|
+
vdi_record = {
|
45
|
+
'name_label' => 'Vagrant disk',
|
46
|
+
'name_description' => 'Base disk uploaded for the vagrant box '+env[:machine].box.name.to_s+' v'+env[:machine].box.version.to_s,
|
47
|
+
'SR' => default_sr,
|
48
|
+
'virtual_size' => "#{virtual_size}",
|
49
|
+
'type' => 'user',
|
50
|
+
'sharable' => false,
|
51
|
+
'read_only' => false,
|
52
|
+
'other_config' => {},
|
53
|
+
'xenstore_data' => {},
|
54
|
+
'sm_config' => {},
|
55
|
+
'tags' => [] }
|
56
|
+
|
57
|
+
vdi_result=env[:xc].call("VDI.create",env[:session],vdi_record)['Value']
|
58
|
+
|
59
|
+
@logger.info("created VDI: " + vdi_result.to_s)
|
60
|
+
vdi_uuid = env[:xc].call("VDI.get_uuid",env[:session],vdi_result)['Value']
|
61
|
+
@logger.info("uuid: "+vdi_uuid)
|
62
|
+
|
63
|
+
# Create a task to so we can get the result of the upload
|
64
|
+
task_result = env[:xc].call("task.create", env[:session], "vagrant-vhd-upload",
|
65
|
+
"Task to track progress of the XVA upload from vagrant")
|
66
|
+
|
67
|
+
if task_result["Status"] != "Success"
|
68
|
+
raise Errors::APIError
|
69
|
+
end
|
70
|
+
|
71
|
+
task = task_result["Value"]
|
72
|
+
|
73
|
+
url = "http://#{hostname}/import_raw_vdi?session_id=#{session}&task_id=#{task}&vdi=#{vdi_result}&format=vhd"
|
74
|
+
|
75
|
+
uploader_options = {}
|
76
|
+
uploader_options[:ui] = env[:ui]
|
77
|
+
|
78
|
+
uploader = MyUtil::Uploader.new(box_vhd_file, url, uploader_options)
|
79
|
+
|
80
|
+
begin
|
81
|
+
uploader.upload!
|
82
|
+
rescue Errors::UploaderInterrupted
|
83
|
+
env[:ui].info(I18n.t("vagrant.xenserver.action.upload_xva.interrupted"))
|
84
|
+
raise
|
85
|
+
end
|
86
|
+
|
87
|
+
task_status = ""
|
88
|
+
|
89
|
+
begin
|
90
|
+
sleep(0.2)
|
91
|
+
task_status_result = env[:xc].call("task.get_status",env[:session],task)
|
92
|
+
if task_status_result["Status"] != "Success"
|
93
|
+
raise Errors::APIError
|
94
|
+
end
|
95
|
+
task_status = task_status_result["Value"]
|
96
|
+
end while task_status == "pending"
|
97
|
+
|
98
|
+
@logger.info("task_status="+task_status)
|
99
|
+
|
100
|
+
if task_status != "success"
|
101
|
+
raise Errors::APIError
|
102
|
+
end
|
103
|
+
|
104
|
+
task_result_result = env[:xc].call("task.get_result",env[:session],task)
|
105
|
+
if task_result_result["Status"] != "Success"
|
106
|
+
raise Errors::APIError
|
107
|
+
end
|
108
|
+
|
109
|
+
task_result = task_result_result["Value"]
|
110
|
+
|
111
|
+
doc = REXML::Document.new(task_result)
|
112
|
+
|
113
|
+
doc.elements.each('value/array/data/value') do |ele|
|
114
|
+
vdi = ele.text
|
115
|
+
end
|
116
|
+
|
117
|
+
@logger.info("task_result=" + task_result)
|
118
|
+
|
119
|
+
tag_result=env[:xc].call("VDI.add_tags",env[:session],vdi_result,vdi_tag)
|
120
|
+
@logger.info("task_result=" + tag_result.to_s)
|
121
|
+
|
122
|
+
env[:box_vdi] = vdi_result
|
123
|
+
else
|
124
|
+
(reference,record) = vdi_ref_rec
|
125
|
+
env[:box_vdi] = reference
|
126
|
+
@logger.info("box_vdi="+reference)
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
@app.call(env)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require "log4r"
|
2
|
+
require "xmlrpc/client"
|
3
|
+
require "vagrant-xenserver/util/uploader"
|
4
|
+
require "rexml/document"
|
5
|
+
|
6
|
+
module VagrantPlugins
|
7
|
+
module XenServer
|
8
|
+
module Action
|
9
|
+
class UploadXVA
|
10
|
+
def initialize(app, env)
|
11
|
+
@app = app
|
12
|
+
@logger = Log4r::Logger.new("vagrant::xenserver::actions::upload_xva")
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
#box_image_file = env[:machine].box.directory.join('export.xva').to_s
|
17
|
+
box_image_file = "/home/jludlam/devel/vagrant-xenserver/test.xva"
|
18
|
+
hostname = env[:machine].provider_config.xs_host
|
19
|
+
session = env[:session]
|
20
|
+
|
21
|
+
@logger.info("box name=" + env[:machine].box.name.to_s)
|
22
|
+
@logger.info("box version=" + env[:machine].box.version.to_s)
|
23
|
+
|
24
|
+
# Create a task to so we can get the result of the upload
|
25
|
+
task_result = env[:xc].call("task.create", env[:session], "vagrant-xva-upload",
|
26
|
+
"Task to track progress of the XVA upload from vagrant")
|
27
|
+
|
28
|
+
if task_result["Status"] != "Success"
|
29
|
+
raise Errors::APIError
|
30
|
+
end
|
31
|
+
|
32
|
+
task = task_result["Value"]
|
33
|
+
|
34
|
+
url = "http://#{hostname}/import?session_id=#{session}&task_id=#{task}"
|
35
|
+
|
36
|
+
uploader_options = {}
|
37
|
+
uploader_options[:ui] = env[:ui]
|
38
|
+
|
39
|
+
uploader = MyUtil::Uploader.new(box_image_file, url, uploader_options)
|
40
|
+
|
41
|
+
begin
|
42
|
+
uploader.upload!
|
43
|
+
rescue Errors::UploaderInterrupted
|
44
|
+
env[:ui].info(I18n.t("vagrant.xenserver.action.upload_xva.interrupted"))
|
45
|
+
raise
|
46
|
+
end
|
47
|
+
|
48
|
+
task_status = ""
|
49
|
+
|
50
|
+
begin
|
51
|
+
sleep(0.2)
|
52
|
+
task_status_result = env[:xc].call("task.get_status",env[:session],task)
|
53
|
+
if task_status_result["Status"] != "Success"
|
54
|
+
raise Errors::APIError
|
55
|
+
end
|
56
|
+
task_status = task_status_result["Value"]
|
57
|
+
end while task_status == "pending"
|
58
|
+
|
59
|
+
@logger.info("task_status="+task_status)
|
60
|
+
|
61
|
+
if task_status != "success"
|
62
|
+
raise Errors::APIError
|
63
|
+
end
|
64
|
+
|
65
|
+
task_result_result = env[:xc].call("task.get_result",env[:session],task)
|
66
|
+
if task_result_result["Status"] != "Success"
|
67
|
+
raise Errors::APIError
|
68
|
+
end
|
69
|
+
|
70
|
+
task_result = task_result_result["Value"]
|
71
|
+
|
72
|
+
doc = REXML::Document.new(task_result)
|
73
|
+
|
74
|
+
doc.elements.each('value/array/data/value') do |ele|
|
75
|
+
@logger.info("ele=" + ele.text)
|
76
|
+
end
|
77
|
+
|
78
|
+
@logger.info("task_result=" + task_result)
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "vagrant"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module XenServer
|
5
|
+
class Config < Vagrant.plugin("2", :config)
|
6
|
+
# The XenServer host name or IP
|
7
|
+
#
|
8
|
+
# @return [String]
|
9
|
+
attr_accessor :xs_host
|
10
|
+
|
11
|
+
# The XenServer username
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
attr_accessor :xs_username
|
15
|
+
|
16
|
+
# The XenServer password
|
17
|
+
#
|
18
|
+
# @return [String]
|
19
|
+
attr_accessor :xs_password
|
20
|
+
|
21
|
+
# True if the VM should be PV
|
22
|
+
#
|
23
|
+
# @return [Bool]
|
24
|
+
attr_accessor :pv
|
25
|
+
|
26
|
+
# Memory settings
|
27
|
+
#
|
28
|
+
# @return [Int]
|
29
|
+
attr_accessor :memory
|
30
|
+
|
31
|
+
def initialize
|
32
|
+
@xs_host = UNSET_VALUE
|
33
|
+
@xs_username = UNSET_VALUE
|
34
|
+
@xs_password = UNSET_VALUE
|
35
|
+
@pv = UNSET_VALUE
|
36
|
+
@memory = UNSET_VALUE
|
37
|
+
end
|
38
|
+
|
39
|
+
def finalize!
|
40
|
+
@xs_host = nil if @xs_host == UNSET_VALUE
|
41
|
+
@xs_username = nil if @xs_username == UNSET_VALUE
|
42
|
+
@xs_password = nil if @xs_password == UNSET_VALUE
|
43
|
+
@pv = nil if @pv == UNSET_VALUE
|
44
|
+
@memory = 1024 if @memory == UNSET_VALUE
|
45
|
+
end
|
46
|
+
|
47
|
+
def validate(machine)
|
48
|
+
errors = _detected_errors
|
49
|
+
errors << I18n.t("vagrant_xenserver.config.host_required") if @xs_host.nil?
|
50
|
+
errors << I18n.t("vagrant_xenserver.config.username_required") if @xs_username.nil?
|
51
|
+
errors << I18n.t("vagrant_xenserver.config.password_required") if @xs_password.nil?
|
52
|
+
|
53
|
+
{ "XenServer Provider" => errors }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "vagrant"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module XenServer
|
5
|
+
module Errors
|
6
|
+
class VagrantXenServerError < Vagrant::Errors::VagrantError
|
7
|
+
error_namespace("vagrant_xenserver.errors")
|
8
|
+
end
|
9
|
+
|
10
|
+
class LoginError < VagrantXenServerError
|
11
|
+
error_key(:login_error)
|
12
|
+
end
|
13
|
+
|
14
|
+
class UploaderInterrupted < VagrantXenServerError
|
15
|
+
error_key(:uploader_interrupted)
|
16
|
+
end
|
17
|
+
|
18
|
+
class UploaderError < VagrantXenServerError
|
19
|
+
error_key(:uploader_error)
|
20
|
+
end
|
21
|
+
|
22
|
+
class APIError < VagrantXenServerError
|
23
|
+
error_key(:api_error)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
begin
|
2
|
+
require "vagrant"
|
3
|
+
rescue LoadError
|
4
|
+
raise "The Vagrant XenServer plugin must be run within Vagrant."
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
module VagrantPlugins
|
9
|
+
module XenServer
|
10
|
+
class Plugin < Vagrant.plugin("2")
|
11
|
+
name "XenServer provider"
|
12
|
+
description <<-DESC
|
13
|
+
This plugin installs a provider that allows Vagrant to manage
|
14
|
+
virtual machines hosted on a XenServer.
|
15
|
+
DESC
|
16
|
+
|
17
|
+
config('xenserver', :provider) do
|
18
|
+
require_relative "config"
|
19
|
+
Config
|
20
|
+
end
|
21
|
+
|
22
|
+
provider('xenserver') do
|
23
|
+
require_relative "provider"
|
24
|
+
Provider
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "vagrant"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module XenServer
|
5
|
+
class Provider < Vagrant.plugin("2", :provider)
|
6
|
+
def initialize(machine)
|
7
|
+
@machine = machine
|
8
|
+
end
|
9
|
+
|
10
|
+
def action(name)
|
11
|
+
action_method = "action_#{name}"
|
12
|
+
return Action.send(action_method) if Action.respond_to?(action_method)
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def ssh_info
|
17
|
+
env = @machine.action('read_ssh_info')
|
18
|
+
env[:machine_ssh_info]
|
19
|
+
end
|
20
|
+
|
21
|
+
def state
|
22
|
+
env = @machine.action("read_state")
|
23
|
+
|
24
|
+
state_id = env[:machine_state_id]
|
25
|
+
|
26
|
+
Vagrant::MachineState.new(state_id, state_id, state_id)
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
id = @machine.id.nil? ? "new" : @machine.id
|
31
|
+
"XenServer (#{id})"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,215 @@
|
|
1
|
+
require "uri"
|
2
|
+
|
3
|
+
require "log4r"
|
4
|
+
|
5
|
+
require "vagrant/util/busy"
|
6
|
+
require "vagrant/util/platform"
|
7
|
+
require "vagrant/util/subprocess"
|
8
|
+
|
9
|
+
module VagrantPlugins
|
10
|
+
module XenServer
|
11
|
+
module MyUtil
|
12
|
+
# This class uploads files using various protocols by subprocessing
|
13
|
+
# to cURL. cURL is a much more capable and complete upload tool than
|
14
|
+
# a hand-rolled Ruby library, so we defer to its expertise.
|
15
|
+
class Uploader
|
16
|
+
# Custom user agent provided to cURL so that requests to URL shorteners
|
17
|
+
# are properly tracked.
|
18
|
+
USER_AGENT = "VagrantXenserver/1.0"
|
19
|
+
|
20
|
+
attr_reader :source
|
21
|
+
attr_reader :destination
|
22
|
+
|
23
|
+
def initialize(source, destination, options=nil)
|
24
|
+
options ||= {}
|
25
|
+
|
26
|
+
@logger = Log4r::Logger.new("vagrant::xenserver::util::uploader")
|
27
|
+
@source = source.to_s
|
28
|
+
@destination = destination.to_s
|
29
|
+
|
30
|
+
begin
|
31
|
+
url = URI.parse(@destination)
|
32
|
+
if url.scheme && url.scheme.start_with?("http") && url.user
|
33
|
+
auth = "#{url.user}"
|
34
|
+
auth += ":#{url.password}" if url.password
|
35
|
+
url.user = nil
|
36
|
+
url.password = nil
|
37
|
+
options[:auth] ||= auth
|
38
|
+
@destination = url.to_s
|
39
|
+
end
|
40
|
+
rescue URI::InvalidURIError
|
41
|
+
# Ignore, since its clearly not HTTP
|
42
|
+
end
|
43
|
+
|
44
|
+
# Get the various optional values
|
45
|
+
@auth = options[:auth]
|
46
|
+
@ca_cert = options[:ca_cert]
|
47
|
+
@ca_path = options[:ca_path]
|
48
|
+
@continue = options[:continue]
|
49
|
+
@headers = options[:headers]
|
50
|
+
@insecure = options[:insecure]
|
51
|
+
@ui = options[:ui]
|
52
|
+
@client_cert = options[:client_cert]
|
53
|
+
end
|
54
|
+
|
55
|
+
# This executes the actual upload, uploading the source file
|
56
|
+
# to the destination with the given options used to initialize this
|
57
|
+
# class.
|
58
|
+
#
|
59
|
+
# If this method returns without an exception, the upload
|
60
|
+
# succeeded. An exception will be raised if the upload failed.
|
61
|
+
def upload!
|
62
|
+
options, subprocess_options = self.options
|
63
|
+
options += ["--output", "dummy"]
|
64
|
+
options << @destination
|
65
|
+
options += ["-T", @source]
|
66
|
+
|
67
|
+
# This variable can contain the proc that'll be sent to
|
68
|
+
# the subprocess execute.
|
69
|
+
data_proc = nil
|
70
|
+
|
71
|
+
if @ui
|
72
|
+
# If we're outputting progress, then setup the subprocess to
|
73
|
+
# tell us output so we can parse it out.
|
74
|
+
subprocess_options[:notify] = :stderr
|
75
|
+
|
76
|
+
progress_data = ""
|
77
|
+
progress_regexp = /(\r(.+?))\r/
|
78
|
+
|
79
|
+
# Setup the proc that'll receive the real-time data from
|
80
|
+
# the uploader.
|
81
|
+
data_proc = Proc.new do |type, data|
|
82
|
+
# Type will always be "stderr" because that is the only
|
83
|
+
# type of data we're subscribed for notifications.
|
84
|
+
|
85
|
+
# Accumulate progress_data
|
86
|
+
progress_data << data
|
87
|
+
|
88
|
+
while true
|
89
|
+
# If we have a full amount of column data (two "\r") then
|
90
|
+
# we report new progress reports. Otherwise, just keep
|
91
|
+
# accumulating.
|
92
|
+
match = progress_regexp.match(progress_data)
|
93
|
+
break if !match
|
94
|
+
data = match[2]
|
95
|
+
progress_data.gsub!(match[1], "")
|
96
|
+
|
97
|
+
# Ignore the first \r and split by whitespace to grab the columns
|
98
|
+
columns = data.strip.split(/\s+/)
|
99
|
+
|
100
|
+
# COLUMN DATA:
|
101
|
+
#
|
102
|
+
# 0 - % total
|
103
|
+
# 1 - Total size
|
104
|
+
# 2 - % received
|
105
|
+
# 3 - Received size
|
106
|
+
# 4 - % transferred
|
107
|
+
# 5 - Transferred size
|
108
|
+
# 6 - Average download speed
|
109
|
+
# 7 - Average upload speed
|
110
|
+
# 9 - Total time
|
111
|
+
# 9 - Time spent
|
112
|
+
# 10 - Time left
|
113
|
+
# 11 - Current speed
|
114
|
+
|
115
|
+
output = "Progress: #{columns[0]}% (Rate: #{columns[11]}/s, Estimated time remaining: #{columns[10]})"
|
116
|
+
@ui.clear_line
|
117
|
+
@ui.detail(output, new_line: false)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
@logger.info("Uploader starting upload: ")
|
123
|
+
@logger.info(" -- Source: #{@source}")
|
124
|
+
@logger.info(" -- Destination: #{@destination}")
|
125
|
+
|
126
|
+
begin
|
127
|
+
execute_curl(options, subprocess_options, &data_proc)
|
128
|
+
ensure
|
129
|
+
# If we're outputting to the UI, clear the output to
|
130
|
+
# avoid lingering progress meters.
|
131
|
+
if @ui
|
132
|
+
@ui.clear_line
|
133
|
+
|
134
|
+
# Windows doesn't clear properly for some reason, so we just
|
135
|
+
# output one more newline.
|
136
|
+
# @ui.detail("") if Platform.windows?
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Everything succeeded
|
141
|
+
true
|
142
|
+
end
|
143
|
+
|
144
|
+
def execute_curl(options, subprocess_options, &data_proc)
|
145
|
+
options = options.dup
|
146
|
+
options << subprocess_options
|
147
|
+
|
148
|
+
# Create the callback that is called if we are interrupted
|
149
|
+
interrupted = false
|
150
|
+
int_callback = Proc.new do
|
151
|
+
@logger.info("Uploader interrupted!")
|
152
|
+
interrupted = true
|
153
|
+
end
|
154
|
+
|
155
|
+
# Execute!
|
156
|
+
result = Vagrant::Util::Busy.busy(int_callback) do
|
157
|
+
Vagrant::Util::Subprocess.execute("curl", *options, &data_proc)
|
158
|
+
end
|
159
|
+
|
160
|
+
# If the upload was interrupted, then raise a specific error
|
161
|
+
raise Errors::UploaderInterrupted if interrupted
|
162
|
+
|
163
|
+
# If it didn't exit successfully, we need to parse the data and
|
164
|
+
# show an error message.
|
165
|
+
if result.exit_code != 0
|
166
|
+
@logger.warn("Uploader exit code: #{result.exit_code}")
|
167
|
+
parts = result.stderr.split(/\n*curl:\s+\(\d+\)\s*/, 2)
|
168
|
+
parts[1] ||= ""
|
169
|
+
raise Errors::UploaderError, message: parts[1].chomp
|
170
|
+
end
|
171
|
+
|
172
|
+
result
|
173
|
+
end
|
174
|
+
|
175
|
+
# Returns the varoius cURL and subprocess options.
|
176
|
+
#
|
177
|
+
# @return [Array<Array, Hash>]
|
178
|
+
def options
|
179
|
+
# Build the list of parameters to execute with cURL
|
180
|
+
options = [
|
181
|
+
"--fail",
|
182
|
+
"--location",
|
183
|
+
"--max-redirs", "10",
|
184
|
+
"--user-agent", USER_AGENT,
|
185
|
+
]
|
186
|
+
|
187
|
+
options += ["--cacert", @ca_cert] if @ca_cert
|
188
|
+
options += ["--capath", @ca_path] if @ca_path
|
189
|
+
options += ["--continue-at", "-"] if @continue
|
190
|
+
options << "--insecure" if @insecure
|
191
|
+
options << "--cert" << @client_cert if @client_cert
|
192
|
+
options << "-u" << @auth if @auth
|
193
|
+
|
194
|
+
if @headers
|
195
|
+
Array(@headers).each do |header|
|
196
|
+
options << "-H" << header
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Specify some options for the subprocess
|
201
|
+
subprocess_options = {}
|
202
|
+
|
203
|
+
# If we're in Vagrant, then we use the packaged CA bundle
|
204
|
+
if Vagrant.in_installer?
|
205
|
+
subprocess_options[:env] ||= {}
|
206
|
+
subprocess_options[:env]["CURL_CA_BUNDLE"] =
|
207
|
+
File.expand_path("cacert.pem", ENV["VAGRANT_INSTALLER_EMBEDDED_DIR"])
|
208
|
+
end
|
209
|
+
|
210
|
+
return [options, subprocess_options]
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|