vanagon 0.15.36 → 0.17.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +48 -23
  3. data/bin/build +4 -25
  4. data/bin/build_host_info +4 -17
  5. data/bin/build_requirements +4 -31
  6. data/bin/inspect +4 -21
  7. data/bin/render +4 -22
  8. data/bin/ship +4 -28
  9. data/bin/sign +4 -11
  10. data/bin/vanagon +7 -0
  11. data/lib/vanagon.rb +1 -1
  12. data/lib/vanagon/cli.rb +94 -0
  13. data/lib/vanagon/cli/build.rb +75 -0
  14. data/lib/vanagon/cli/build_host_info.rb +49 -0
  15. data/lib/vanagon/cli/build_requirements.rb +60 -0
  16. data/lib/vanagon/cli/inspect.rb +65 -0
  17. data/lib/vanagon/cli/render.rb +51 -0
  18. data/lib/vanagon/cli/ship.rb +52 -0
  19. data/lib/vanagon/cli/sign.rb +34 -0
  20. data/lib/vanagon/driver.rb +11 -7
  21. data/lib/vanagon/engine/always_be_scheduling.rb +271 -1
  22. data/lib/vanagon/engine/docker.rb +101 -14
  23. data/lib/vanagon/engine/pooler.rb +7 -3
  24. data/lib/vanagon/platform.rb +5 -3
  25. data/lib/vanagon/platform/deb.rb +1 -1
  26. data/lib/vanagon/platform/dsl.rb +11 -0
  27. data/lib/vanagon/platform/rpm.rb +1 -1
  28. data/lib/vanagon/platform/windows.rb +29 -2
  29. data/lib/vanagon/project.rb +23 -4
  30. data/lib/vanagon/project/dsl.rb +33 -0
  31. data/lib/vanagon/utilities.rb +30 -8
  32. data/resources/rpm/project.spec.erb +3 -0
  33. data/spec/lib/vanagon/cli_spec.rb +80 -0
  34. data/spec/lib/vanagon/engine/always_be_scheduling_spec.rb +113 -1
  35. data/spec/lib/vanagon/engine/docker_spec.rb +74 -16
  36. data/spec/lib/vanagon/engine/ec2_spec.rb +2 -0
  37. data/spec/lib/vanagon/engine/pooler_spec.rb +1 -1
  38. data/spec/spec_helper.rb +1 -0
  39. metadata +56 -33
  40. data/lib/vanagon/optparse.rb +0 -86
  41. data/spec/lib/vanagon/optparse_spec.rb +0 -64
@@ -10,6 +10,7 @@ class Vanagon
10
10
 
11
11
  @docker_cmd = Vanagon::Utilities.find_program_on_path('docker')
12
12
  @required_attributes << "docker_image"
13
+ @required_attributes.delete('ssh_port') if @platform.use_docker_exec
13
14
  end
14
15
 
15
16
  # Get the engine name
@@ -33,25 +34,16 @@ class Vanagon
33
34
  # This method is used to obtain a vm to build upon using
34
35
  # a docker container.
35
36
  # @raise [Vanagon::Error] if a target cannot be obtained
36
- def select_target # rubocop:disable Metrics/AbcSize
37
+ def select_target
38
+ ssh_args = @platform.use_docker_exec ? '' : "-p #{@platform.ssh_port}:22"
37
39
  extra_args = @platform.docker_run_args.nil? ? [] : @platform.docker_run_args
38
40
 
39
- Vanagon::Utilities.ex("#{@docker_cmd} run -d --name #{build_host_name}-builder -p #{@platform.ssh_port}:22 #{extra_args.join(' ')} #{@platform.docker_image}")
41
+ Vanagon::Utilities.ex("#{@docker_cmd} run -d --name #{build_host_name}-builder #{ssh_args} #{extra_args.join(' ')} #{@platform.docker_image}")
40
42
  @target = 'localhost'
41
43
 
42
- # Wait for ssh to come up in the container. Retry 5 times with a 1
43
- # second sleep between errors to account for network resets while SSHD
44
- # is starting. Allow a maximum of 5 seconds for SSHD to start.
45
- Vanagon::Utilities.retry_with_timeout(5, 5) do
46
- begin
47
- Vanagon::Utilities.remote_ssh_command("#{@target_user}@#{@target}", 'exit', @platform.ssh_port)
48
- rescue StandardError => e
49
- sleep(1) # Give SSHD some time to start.
50
- raise e
51
- end
52
- end
44
+ wait_for_ssh unless @platform.use_docker_exec
53
45
  rescue StandardError => e
54
- raise Vanagon::Error.wrap(e, "Something went wrong getting a target vm to build on using docker. Ssh was not up in the container after 5 seconds.")
46
+ raise Vanagon::Error.wrap(e, "Something went wrong getting a target vm to build on using Docker.")
55
47
  end
56
48
 
57
49
  # This method is used to tell the vmpooler to delete the instance of the
@@ -62,6 +54,101 @@ class Vanagon
62
54
  rescue Vanagon::Error => e
63
55
  warn "There was a problem tearing down the docker container #{build_host_name}-builder (#{e.message})."
64
56
  end
57
+
58
+ def dispatch(command, return_output = false)
59
+ if @platform.use_docker_exec
60
+ docker_exec(command, return_output)
61
+ else
62
+ super
63
+ end
64
+ end
65
+
66
+ def ship_workdir(workdir)
67
+ if @platform.use_docker_exec
68
+ docker_cp_globs_to("#{workdir}/*", @remote_workdir)
69
+ else
70
+ super
71
+ end
72
+ end
73
+
74
+ def retrieve_built_artifact(artifacts_to_fetch, no_packaging)
75
+ if @platform.use_docker_exec
76
+ output_path = 'output/'
77
+ FileUtils.mkdir_p(output_path)
78
+ unless no_packaging
79
+ artifacts_to_fetch << "#{@remote_workdir}/output/*"
80
+ end
81
+
82
+ docker_cp_globs_from(artifacts_to_fetch, 'output/')
83
+ else
84
+ super
85
+ end
86
+ end
87
+
88
+ # Execute a command on a container via docker exec
89
+ def docker_exec(command, return_output = false)
90
+ command = command.gsub("'", "'\\\\''")
91
+ Vanagon::Utilities.local_command("#{@docker_cmd} exec #{build_host_name}-builder /bin/sh -c '#{command}'",
92
+ return_command_output: return_output)
93
+ end
94
+
95
+ # Copy files between a container and the host
96
+ def docker_cp(source, target)
97
+ Vanagon::Utilities.ex("#{@docker_cmd} cp '#{source}' '#{target}'")
98
+ end
99
+
100
+ # Copy files matching a glob pattern from the host to the container
101
+ def docker_cp_globs_to(globs, container_path)
102
+ Array(globs).each do |glob|
103
+ Dir.glob(glob).each do |path|
104
+ docker_cp(path, "#{build_host_name}-builder:#{container_path}")
105
+ end
106
+ end
107
+ end
108
+
109
+ # Copy files matching a glob pattern from the container to the host
110
+ #
111
+ # @note Globs are expanded by running `/bin/sh` in the container, which
112
+ # may not support the same variety of expressions as Ruby's `Dir.glob`.
113
+ # For example, `**` may not work.
114
+ def docker_cp_globs_from(globs, host_path)
115
+ Array(globs).each do |glob|
116
+ # Match the behavior of `rsync -r` when both paths are directories
117
+ # by copying the contents of the directory instead of the directory.
118
+ glob += '*' if glob.end_with?('/') && host_path.end_with?('/')
119
+
120
+ # TODO: This doesn't handle "interesting" paths. E.g. paths with
121
+ # spaces or other special non-glob characters. This could be
122
+ # fixed with a variant of `Shellwords.shellescape` that allows
123
+ # glob characters to pass through.
124
+ paths = docker_exec(%(for file in #{glob};do [ -e "$file" ] && printf '%s\\0' "${file}";done), true).split("\0")
125
+
126
+ paths.each do |path|
127
+ docker_cp("#{build_host_name}-builder:#{path}", host_path)
128
+ end
129
+ end
130
+ end
131
+
132
+ # Wait for ssh to come up in the container
133
+ #
134
+ # Retry 5 times with a 1 second sleep between errors to account for
135
+ # network resets while SSHD is starting. Allow a maximum of 5 seconds for
136
+ # SSHD to start.
137
+ #
138
+ # @raise [Vanagon::Error] if a SSH connection cannot be established.
139
+ # @return [void]
140
+ def wait_for_ssh
141
+ Vanagon::Utilities.retry_with_timeout(5, 5) do
142
+ begin
143
+ Vanagon::Utilities.remote_ssh_command("#{@target_user}@#{@target}", 'exit', @platform.ssh_port)
144
+ rescue StandardError => e
145
+ sleep(1) # Give SSHD some time to start.
146
+ raise e
147
+ end
148
+ end
149
+ rescue StandardError => e
150
+ raise Vanagon::Error.wrap(e, "SSH was not up in the container after 5 seconds.")
151
+ end
65
152
  end
66
153
  end
67
154
  end
@@ -1,6 +1,10 @@
1
1
  require 'vanagon/engine/base'
2
2
  require 'yaml'
3
3
 
4
+ ### Note this class is deprecated in favor of using the ABS Engine. The pooler has changed it's API with regards to
5
+ # getting VMs for ondemand provisioning and would need to be updated here.
6
+ # See DIO-1066
7
+
4
8
  class Vanagon
5
9
  class Engine
6
10
  class Pooler < Base
@@ -10,7 +14,7 @@ class Vanagon
10
14
  def initialize(platform, target = nil, **opts)
11
15
  super
12
16
 
13
- @available_poolers = ["http://vmpooler.delivery.puppetlabs.net", "https://nspooler-service-prod-1.delivery.puppetlabs.net"]
17
+ @available_poolers = ["https://vmpooler.delivery.puppetlabs.net", "https://nspooler-service-prod-1.delivery.puppetlabs.net"]
14
18
  @token = load_token
15
19
  @required_attributes << "vmpooler_template"
16
20
  end
@@ -63,7 +67,7 @@ class Vanagon
63
67
 
64
68
  # Read a vmpooler token from the yaml formatted vmfloaty config,
65
69
  # as outlined by the vmfloaty project:
66
- # https://github.com/briancain/vmfloaty
70
+ # https://github.com/puppetlabs/vmfloaty
67
71
  #
68
72
  # @return [String, nil] the vmfloaty vmpooler token value
69
73
  def read_vmfloaty_token(path = "~/.vmfloaty.yml")
@@ -75,7 +79,7 @@ class Vanagon
75
79
  end
76
80
  private :read_vmfloaty_token
77
81
 
78
- # This method is used to obtain a vm to build upon using the Puppet Labs'
82
+ # This method is used to obtain a vm to build upon using Puppet's internal
79
83
  # vmpooler (https://github.com/puppetlabs/vmpooler) or other pooler technologies
80
84
  # leveraging the same API
81
85
  # @raise [Vanagon::Error] if a target cannot be obtained
@@ -115,6 +115,7 @@ class Vanagon
115
115
  # Docker engine specific
116
116
  attr_accessor :docker_image
117
117
  attr_accessor :docker_run_args
118
+ attr_accessor :use_docker_exec
118
119
 
119
120
  # AWS engine specific
120
121
  attr_accessor :aws_ami
@@ -238,6 +239,8 @@ class Vanagon
238
239
  @copy ||= "cp"
239
240
  @shasum ||= "sha1sum"
240
241
 
242
+ @use_docker_exec = false
243
+
241
244
  # Our first attempt at defining metadata about a platform
242
245
  @cross_compiled ||= false
243
246
  @valid_operators ||= ['<', '>', '<=', '>=', '=']
@@ -486,9 +489,9 @@ class Vanagon
486
489
  def generate_compiled_archive(project)
487
490
  name_and_version = "#{project.name}-#{project.version}"
488
491
  name_and_version_and_platform = "#{name_and_version}.#{name}"
492
+ name_and_platform = "#{project.name}.#{name}"
489
493
  final_archive = "output/#{name_and_version_and_platform}.tar.gz"
490
494
  archive_directory = "#{project.name}-archive"
491
- metadata = project.build_manifest_json(true)
492
495
 
493
496
  # previously, we weren't properly handling the case of custom BOM paths.
494
497
  # If we have a custom BOM path, during Makefile execution, the top-level
@@ -503,7 +506,6 @@ class Vanagon
503
506
  bill_of_materials_command = "mv .#{project.bill_of_materials.path}/bill-of-materials ../.."
504
507
  end
505
508
 
506
- metadata.gsub!(/\n/, '\n')
507
509
  [
508
510
  "mkdir output",
509
511
  "mkdir #{archive_directory}",
@@ -511,7 +513,7 @@ class Vanagon
511
513
  "rm #{name_and_version}.tar.gz",
512
514
  "cd #{archive_directory}/#{name_and_version}; #{bill_of_materials_command}; #{tar} cf ../../#{name_and_version_and_platform}.tar *",
513
515
  "gzip -9c #{name_and_version_and_platform}.tar > #{name_and_version_and_platform}.tar.gz",
514
- "echo -e \"#{metadata}\" > output/#{name_and_version_and_platform}.json",
516
+ "cp build_metadata.#{name_and_platform}.json output/#{name_and_version_and_platform}.json",
515
517
  "cp bill-of-materials output/#{name_and_version_and_platform}-bill-of-materials ||:",
516
518
  "cp #{name_and_version_and_platform}.tar.gz output",
517
519
  "#{shasum} #{final_archive} > #{final_archive}.sha1"
@@ -140,7 +140,7 @@ class Vanagon
140
140
  @tar = "tar"
141
141
  @patch = "/usr/bin/patch"
142
142
  @num_cores = "/usr/bin/nproc"
143
- @curl = "curl --silent --show-error --fail"
143
+ @curl = "curl --silent --show-error --fail --location"
144
144
  @valid_operators = ['<', '>', '<=', '>=', '=', '<<', '>>']
145
145
  super(name)
146
146
  end
@@ -284,6 +284,17 @@ class Vanagon
284
284
  @platform.docker_run_args = Array(args)
285
285
  end
286
286
 
287
+ # Specify whether to use Docker exec instead of SSH to run commands
288
+ #
289
+ # This also causes Vanagon to use `docker cp` instead of `rsync` when
290
+ # copying files.
291
+ #
292
+ # @param bool [Boolean] a boolean value indicating whether to use
293
+ # `docker exec` and `docker cp` over `ssh` and `rsync`.
294
+ def use_docker_exec(bool)
295
+ @platform.use_docker_exec = bool
296
+ end
297
+
287
298
  # Set the ami for the platform to use
288
299
  #
289
300
  # @param ami [String] the ami id used.
@@ -103,7 +103,7 @@ class Vanagon
103
103
  @patch ||= "/usr/bin/patch"
104
104
  @num_cores ||= "/bin/grep -c 'processor' /proc/cpuinfo"
105
105
  @rpmbuild ||= "/usr/bin/rpmbuild"
106
- @curl = "curl --silent --show-error --fail"
106
+ @curl = "curl --silent --show-error --fail --location"
107
107
  super(name)
108
108
  end
109
109
  end
@@ -205,11 +205,36 @@ class Vanagon
205
205
  # "Misc Dir for versions.txt, License file and Icon file"
206
206
  misc_dir = "SourceDir/#{project.settings[:base_dir]}/#{project.settings[:company_id]}/#{project.settings[:product_id]}/misc"
207
207
  # Actual array of commands to be written to the Makefile
208
- [
208
+ make_commands = [
209
209
  "mkdir -p output/#{target_dir}",
210
210
  "mkdir -p $(tempdir)/{SourceDir,wix/wixobj}",
211
211
  "#{@copy} -r wix/* $(tempdir)/wix/",
212
- "gunzip -c #{project.name}-#{project.version}.tar.gz | '#{@tar}' -C '$(tempdir)/SourceDir' --strip-components 1 -xf -",
212
+ "gunzip -c #{project.name}-#{project.version}.tar.gz | '#{@tar}' -C '$(tempdir)/SourceDir' --strip-components 1 -xf -"
213
+ ]
214
+
215
+ unless project.extra_files_to_sign.empty?
216
+ begin
217
+ tempdir = nil
218
+ # Skip signing extra files if logging into the signing_host fails
219
+ # This enables things like CI being able to sign the additional files,
220
+ # but locally triggered builds by developers who don't have access to
221
+ # the signing host just print a message and skip the signing.
222
+ Vanagon::Utilities.retry_with_timeout(3, 5) do
223
+ tempdir = Vanagon::Utilities::remote_ssh_command("#{project.signing_username}@#{project.signing_hostname}", "#{@mktemp} 2>/dev/null", return_command_output: true)
224
+ end
225
+ project.extra_files_to_sign.each do |file|
226
+ file_location = File.join(tempdir, File.basename(file))
227
+ make_commands << [
228
+ "rsync -e '#{Vanagon::Utilities.ssh_command}' -rHlv --no-perms --no-owner --no-group #{File.join('$(tempdir)', 'SourceDir', file)} #{project.signing_username}@#{project.signing_hostname}:#{tempdir}",
229
+ "#{Vanagon::Utilities.ssh_command} #{project.signing_username}@#{project.signing_hostname} #{project.signing_command} #{file_location}",
230
+ "rsync -e '#{Vanagon::Utilities.ssh_command}' -rHlv -O --no-perms --no-owner --no-group #{project.signing_username}@#{project.signing_hostname}:#{file_location} #{File.join('$(tempdir)', 'SourceDir', file)}"
231
+ ]
232
+ end
233
+ rescue RuntimeError
234
+ warn "Unable to connect to #{project.signing_username}@#{project.signing_hostname}, skipping signing extra files: #{project.extra_files_to_sign.join(',')}"
235
+ end
236
+ end
237
+ make_commands << [
213
238
  "mkdir -p $(tempdir)/#{misc_dir}",
214
239
  # Need to use awk here to convert to DOS format so that notepad can display file correctly.
215
240
  "awk 'sub(\"$$\", \"\\r\")' $(tempdir)/SourceDir/bill-of-materials > $(tempdir)/#{misc_dir}/versions.txt",
@@ -225,6 +250,8 @@ class Vanagon
225
250
  # -loc is required for the UI localization it points to the actual localization .wxl
226
251
  "cd $(tempdir)/wix/wixobj; \"$$WIX/bin/light.exe\" #{light_flags} -b $$(cygpath -aw $(tempdir)) -loc $$(cygpath -aw $(tempdir)/wix/localization/puppet_en-us.wxl) -out $$(cygpath -aw $(workdir)/output/#{target_dir}/#{msi_package_name(project)}) *.wixobj",
227
252
  ]
253
+
254
+ make_commands.flatten
228
255
  end
229
256
 
230
257
  # Method to derive the msi (Windows Installer) package name for the project.
@@ -108,6 +108,14 @@ class Vanagon
108
108
  # you just want to perform installation and pull down a file.
109
109
  attr_accessor :no_packaging
110
110
 
111
+ # Extra files to sign
112
+ # Right now just supported on windows, useful for signing powershell scripts
113
+ # that need to be signed between build and MSI creation
114
+ attr_accessor :extra_files_to_sign
115
+ attr_accessor :signing_hostname
116
+ attr_accessor :signing_username
117
+ attr_accessor :signing_command
118
+
111
119
  # Loads a given project from the configdir
112
120
  #
113
121
  # @param name [String] the name of the project
@@ -156,6 +164,10 @@ class Vanagon
156
164
  @upstream_metadata = {}
157
165
  @no_packaging = false
158
166
  @artifacts_to_fetch = []
167
+ @extra_files_to_sign = []
168
+ @signing_hostname = ''
169
+ @signing_username = ''
170
+ @signing_command = ''
159
171
  end
160
172
 
161
173
  # Magic getter to retrieve settings in the project
@@ -714,20 +726,27 @@ class Vanagon
714
726
  # Writes a json file at `ext/build_metadata.<project>.<platform>.json` containing information
715
727
  # about what went into a built artifact
716
728
  #
717
- # @return [Hash] of build information
718
- def save_manifest_json(platform)
729
+ # @param platform [String] platform we're writing metadata for
730
+ # @param additional_directories [String|Array[String]] additional
731
+ # directories to write build_metadata.<project>.<platform>.json to
732
+ def save_manifest_json(platform, additional_directories = nil) # rubocop:disable Metrics/AbcSize
719
733
  manifest = build_manifest_json
720
734
  metadata = metadata_merge(manifest, @upstream_metadata)
721
735
 
722
736
  ext_directory = 'ext'
723
737
  FileUtils.mkdir_p ext_directory
724
738
 
739
+ directories = [ext_directory, additional_directories].compact
725
740
  metadata_file_name = "build_metadata.#{name}.#{platform.name}.json"
726
- File.open(File.join(ext_directory, metadata_file_name), 'w') do |f|
727
- f.write(JSON.pretty_generate(metadata))
741
+ directories.each do |directory|
742
+ File.open(File.join(directory, metadata_file_name), 'w') do |f|
743
+ f.write(JSON.pretty_generate(metadata))
744
+ end
728
745
  end
729
746
 
730
747
  ## VANAGON-132 Backwards compatibility: make a 'build_metadata.json' file
748
+ # No need to propagate this backwards compatibility to the new additional
749
+ # directories
731
750
  File.open(File.join(ext_directory, 'build_metadata.json'), 'w') do |f|
732
751
  f.write(JSON.pretty_generate(metadata))
733
752
  end
@@ -363,6 +363,39 @@ class Vanagon
363
363
  def no_packaging(var)
364
364
  @project.no_packaging = var
365
365
  end
366
+
367
+ # Set to sign additional files during buildtime. Only implemented for
368
+ # windows. Can be specified more than once
369
+ #
370
+ # @param [String] file to sign
371
+ def extra_file_to_sign(file)
372
+ @project.extra_files_to_sign << file
373
+ end
374
+
375
+ # The hostname to sign additional files on. Only does anything when there
376
+ # are extra files to sign
377
+ #
378
+ # @param [String] hostname of the machine to run the extra file signing on
379
+ def signing_hostname(hostname)
380
+ @project.signing_hostname = hostname
381
+ end
382
+
383
+ # The username to log in to the signing_hostname as. Only does anything
384
+ # when there are extra files to sign
385
+ #
386
+ # @param [String] the username to log in to `signing_hostname` as
387
+ def signing_username(username)
388
+ @project.signing_username = username
389
+ end
390
+
391
+ # The command to run to sign additional files. The command should assume
392
+ # it will have the file path appended to the end of the command, since
393
+ # files end up in a temp directory.
394
+ #
395
+ # @param [String] the command to sign additional files
396
+ def signing_command(command)
397
+ @project.signing_command = command
398
+ end
366
399
  end
367
400
  end
368
401
  end
@@ -39,17 +39,16 @@ class Vanagon
39
39
  end
40
40
 
41
41
  # Simple wrapper around Net::HTTP. Will make a request of the given type to
42
- # the given url and return the body as parsed by JSON.
42
+ # the given url and return the response object
43
43
  #
44
44
  # @param url [String] The url to make the request against (needs to be parsable by URI
45
45
  # @param type [String] One of the supported request types (currently 'get', 'post', 'delete')
46
46
  # @param payload [String] The request body data payload used for POST and PUT
47
47
  # @param header [Hash] Send additional information in the HTTP request header
48
- # @return [Hash] The response body is parsed by JSON and returned
48
+ # @return [Net::HTTPAccepted] The response object
49
49
  # @raise [RuntimeError, Vanagon::Error] an exception is raised if the
50
- # action is not supported, or if there is a problem with the http request,
51
- # or if the response is not JSON
52
- def http_request(url, type, payload = {}.to_json, header = nil) # rubocop:disable Metrics/AbcSize
50
+ # action is not supported, or if there is a problem with the http request
51
+ def http_request_generic(url, type, payload = {}.to_json, header = nil) # rubocop:disable Metrics/AbcSize
53
52
  uri = URI.parse(url)
54
53
  http = Net::HTTP.new(uri.host, uri.port)
55
54
  http.use_ssl = true if uri.scheme == 'https'
@@ -77,14 +76,37 @@ class Vanagon
77
76
  end
78
77
 
79
78
  response = http.request(request)
80
-
81
- JSON.parse(response.body)
79
+ response
82
80
  rescue Errno::ETIMEDOUT, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
83
81
  EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
84
82
  Net::ProtocolError => e
85
83
  raise Vanagon::Error.wrap(e, "Problem reaching #{url}. Is #{uri.host} down?")
84
+ end
85
+
86
+ # uses http_request_generic and returns the body as parsed by JSON.
87
+ # @param url [String] The url to make the request against (needs to be parsable by URI
88
+ # @param type [String] One of the supported request types (currently 'get', 'post', 'delete')
89
+ # @param payload [String] The request body data payload used for POST and PUT
90
+ # @param header [Hash] Send additional information in the HTTP request header
91
+ # @return [Hash] The response in JSON format
92
+ # @raise [RuntimeError, Vanagon::Error] an exception is raised if the response
93
+ # body cannot be parsed as JSON
94
+ def http_request(url, type, payload = {}.to_json, header = nil)
95
+ response = http_request_generic(url, type, payload, header)
96
+ JSON.parse(response.body)
86
97
  rescue JSON::ParserError => e
87
- raise Vanagon::Error.wrap(e, "#{uri.host} handed us a response that doesn't look like JSON.")
98
+ raise Vanagon::Error.wrap(e, "#{url} handed us a response that doesn't look like JSON.")
99
+ end
100
+
101
+ # uses http_request_generic and returns the response code.
102
+ # @param url [String] The url to make the request against (needs to be parsable by URI
103
+ # @param type [String] One of the supported request types (currently 'get', 'post', 'delete')
104
+ # @param payload [String] The request body data payload used for POST and PUT
105
+ # @param header [Hash] Send additional information in the HTTP request header
106
+ # @return [String] The response code eg 202, 200 etc
107
+ def http_request_code(url, type, payload = {}.to_json, header = nil)
108
+ response = http_request_generic(url, type, payload, header)
109
+ response.code
88
110
  end
89
111
 
90
112
  # Similar to rake's sh, the passed command will be executed and an