Class: Mixlib::Install::Backend::Bintray

Inherits:
Base
  • Object
show all
Defined in:
lib/mixlib/install/backend/bintray.rb

Defined Under Namespace

Classes: UnknownArchitecture, VersionNotFound

Constant Summary collapse

BINTRAY_USERNAME =

Bintray credentials for api read access. These are here intentionally.

"mixlib-install@chef".freeze
BINTRAY_PASSWORD =
"a83d3a2ffad50eb9a2230f281a2e19b70fe0db2d".freeze
ENDPOINT =
"https://bintray.com/api/v1/".freeze
DOWNLOAD_URL_ENDPOINT =
"https://packages.chef.io".freeze
COMPAT_DOWNLOAD_URL_ENDPOINT =
"http://chef.bintray.com".freeze

Instance Attribute Summary

Attributes inherited from Base

#options

Instance Method Summary collapse

Methods inherited from Base

#filter_artifacts, #info, #initialize, #platform_filters_available?

Constructor Details

This class inherits a constructor from Mixlib::Install::Backend::Base

Instance Method Details

#available_artifactsArray<ArtifactInfo>

Get artifacts for a given version, channel and product_name

Returns:



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
# File 'lib/mixlib/install/backend/bintray.rb', line 93

def available_artifacts
  version = options.latest_version? ? latest_version : options.product_version
  begin
    results = bintray_get("#{options.channel}/#{options.product_name}/versions/#{version}/files")
  rescue Net::HTTPServerException => e
    if e.message =~ /404 "Not Found"/
      raise VersionNotFound,
        "Specified version (#{version}) not found for #{options.product_name} in #{options.channel} channel."
    else
      raise
    end
  end

  #
  # Delete files that we don't want as part of the artifact info array
  # Windows: .asc files
  # MAC OS _X: .pkg files which are uploaded along with dmg files for
  # some chef versions.
  #
  %w{ asc pkg }.each do |ext|
    results.reject! { |r| r["name"].end_with?(".#{ext}") }
  end

  # Convert results to build records
  results.map! { |a| create_artifact(a) }

  windows_artifact_fixup!(results)
end

#bintray_get(path) ⇒ String

Makes a GET request to bintray for the given path.

Parameters:

  • path (String)

    “/api/v1/packages/chef” is prepended to the given path.

Returns:

  • (String)

    JSON parsed string of the bintray response



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/mixlib/install/backend/bintray.rb', line 62

def bintray_get(path)
  uri = URI.parse(endpoint)
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = (uri.scheme == "https")

  full_path = File.join(uri.path, "packages/chef", path)
  request = Net::HTTP::Get.new(full_path)
  request.basic_auth(BINTRAY_USERNAME, BINTRAY_PASSWORD)

  res = http.request(request)

  # Raise if response is not 2XX
  res.value
  JSON.parse(res.body)
end

#create_artifact(artifact_map) ⇒ ArtifactInfo

Creates an instance of ArtifactInfo

"name" => "chef-12.8.1-1.powerpc.bff",
"path" => "aix/6.1/chef-12.8.1-1.powerpc.bff",
"version" => "12.8.1",
"sha1" => "1206f7be7be8bbece1e9943dcdc0d22fe538718b",
"sha256" => "e49321095a04f51385a59b3f3d7223cd1bddefc2e2f4280edfb0934d00a4fa3f"

Parameters:

  • artifact_map

Returns:



170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/mixlib/install/backend/bintray.rb', line 170

def create_artifact(artifact_map)
  platform_info = parse_platform_info(artifact_map)

  ArtifactInfo.new(
    sha1:             artifact_map["sha1"],
    sha256:           artifact_map["sha256"],
    version:          artifact_map["version"],
    platform:         platform_info[:platform],
    platform_version: platform_info[:platform_version],
    architecture:     platform_info[:architecture],
    url:              url(artifact_map)
  )
end

#endpointObject



50
51
52
# File 'lib/mixlib/install/backend/bintray.rb', line 50

def endpoint
  @endpoint ||= ENV.fetch("BINTRAY_ENDPOINT", ENDPOINT)
end

#latest_versionString

Get latest version for product/channel

Returns:

  • (String)

    latest version value



83
84
85
86
# File 'lib/mixlib/install/backend/bintray.rb', line 83

def latest_version
  result = bintray_get("#{options.channel}/#{options.product_name}/versions/_latest")
  result["name"]
end

#normalize_platform(platform, platform_version) ⇒ Object

Normalizes platform and platform_version information that we receive from bintray. There are a few entries that we historically published that we need to normalize. They are:

* solaris -> solaris2 & 10 -> 5.10 for solaris.

Parameters:

  • platform (String)
  • platform_version (String)


251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/mixlib/install/backend/bintray.rb', line 251

def normalize_platform(platform, platform_version)
  if platform == "solaris"
    platform = "solaris2"

    # Here platform_version is set to either 10 or 11 and we would like
    # to normalize that to 5.10 and 5.11.

    platform_version = "5.#{platform_version}"
  end

  [platform, platform_version]
end

#parse_architecture_from_file_name(filename) ⇒ String

Determines the architecture for which a file is published from from filename.

We determine the architecture based on the filename of the artifact since architecture the artifact is published for is not available in bintray.

IMPORTANT: This function is heavily used by omnitruck poller. Make

sure you test with `./poller` if you change this function.

Parameters:

  • filename (String)

Returns:

  • (String)

    one of the standardized architectures for Chef packages: x86_64, i386, powerpc, sparc, ppc64, ppc64le



280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'lib/mixlib/install/backend/bintray.rb', line 280

def parse_architecture_from_file_name(filename)
  #
  # We first map the different variations of architectures that we have
  # used historically to our final set.
  #
  if %w{ x86_64 amd64 x64 }.fuzzy_include?(filename)
    "x86_64"
  elsif %w{ i386 x86 i86pc i686 }.fuzzy_include?(filename)
    "i386"
  elsif %w{ powerpc }.fuzzy_include?(filename)
    "powerpc"
  elsif %w{ sparc sun4u sun4v }.fuzzy_include?(filename)
    "sparc"
  # Note that ppc64le should come before ppc64 otherwise our search
  # will think ppc64le matches ppc64. Ubuntu also calls it ppc64el.
  elsif %w{ ppc64le ppc64el }.fuzzy_include?(filename)
    "ppc64le"
  elsif %w{ ppc64 }.fuzzy_include?(filename)
    "ppc64"
  #
  # From here on we need to deal with historical versions
  # that we have published without any architecture in their
  # names.
  #
  #
  # All dmg files are published for x86_64
  elsif filename.end_with?(".dmg")
    "x86_64"
  #
  # The msi files we catch here are versions that are older than the
  # ones which we introduced 64 builds. Therefore they should map to
  # i386
  elsif filename.end_with?(".msi")
    "i386"
  #
  # sh files are the packaging format we were using before dmg on Mac.
  # They map to x86_64
  elsif filename.end_with?(".sh")
    "x86_64"
  #
  # We have two common file names for solaris packages. E.g:
  #   chef-11.12.8-2.solaris2.5.10.solaris
  #   chef-11.12.8-2.solaris2.5.9.solaris
  # These were build on two boxes:
  #   Solaris 9 => sparc
  #   Solaris 10 => i386
  elsif filename.end_with?(".solaris2.5.10.solaris")
    "i386"
  elsif filename.end_with?(".solaris2.5.9.solaris")
    "sparc"
  else
    raise UnknownArchitecture,
      "architecture can not be determined for '#{filename}'"
  end
end

#parse_platform_info(artifact_map) ⇒ Hash

Parses platform info

"name" => "chef-12.8.1-1.powerpc.bff",
"path" => "aix/6.1/chef-12.8.1-1.powerpc.bff",
"version" => "12.8.1",
"sha1" => "1206f7be7be8bbece1e9943dcdc0d22fe538718b",
"sha256" => "e49321095a04f51385a59b3f3d7223cd1bddefc2e2f4280edfb0934d00a4fa3f"

Parameters:

  • artifact_map

Returns:

  • (Hash)

    platform, platform_version, architecture



224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/mixlib/install/backend/bintray.rb', line 224

def parse_platform_info(artifact_map)
  # platform/platform_version/filename
  path = artifact_map["path"].split("/")
  platform = path[0]
  platform_version = path[1]
  platform, platform_version = normalize_platform(platform, platform_version)

  filename = artifact_map["name"]
  architecture = parse_architecture_from_file_name(filename)

  {
    platform: platform,
    platform_version: platform_version,
    architecture: architecture,
  }
end

#url(artifact_map) ⇒ String

Creates the URL for the artifact.

For some older platform & platform_version combinations we need to use COMPAT_DOWNLOAD_URL_ENDPOINT since these versions have an OpenSSL version that can not verify the DOWNLOAD_URL_ENDPOINT based urls

Parameters:

  • artifact_map

    see #create_artifact for details.

Returns:

  • (String)

    url for the artifact



197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/mixlib/install/backend/bintray.rb', line 197

def url(artifact_map)
  platform_info = parse_platform_info(artifact_map)

  base_url = case "#{platform_info[:platform]}-#{platform_info[:platform_version]}"
             when "freebsd-9", "el-5", "solaris2-5.9", "solaris2-5.10"
               COMPAT_DOWNLOAD_URL_ENDPOINT
             else
               DOWNLOAD_URL_ENDPOINT
             end

  "#{base_url}/#{options.channel}/#{artifact_map["path"]}"
end

#windows_artifact_fixup!(artifacts) ⇒ Object

On windows, if we do not have a native 64-bit package available in the discovered artifacts, we will make 32-bit artifacts available for 64-bit architecture.



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
# File 'lib/mixlib/install/backend/bintray.rb', line 125

def windows_artifact_fixup!(artifacts)
  new_artifacts = [ ]
  native_artifacts = [ ]

  artifacts.each do |r|
    next if r.platform != "windows"

    # Store all native 64-bit artifacts and clone 32-bit artifacts to
    # be used as 64-bit.
    case r.architecture
    when "i386"
      new_artifacts << r.clone_with(architecture: "x86_64")
    when "x86_64"
      native_artifacts << r.clone
    else
      puts "Unknown architecture '#{r.architecture}' for windows."
    end
  end

  # Now discard the cloned artifacts if we find an equivalent native
  # artifact
  native_artifacts.each do |r|
    new_artifacts.delete_if do |x|
      x.platform_version == r.platform_version
    end
  end

  # add the remaining cloned artifacts to the original set
  artifacts += new_artifacts
end