Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add miq_vagrant_master script #13

Merged
merged 1 commit into from
Jul 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions miq_vagrant_master/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
`miq_vagrant_master`
====================

This is a helper script for fetching a up to date `vagrant` box for the nightly
`master` build from [http://releases.manageiq.org/][1] in a versioned manner.

Doing this requires creating a `metadata.json` file that vagrant can use to
determine what the available versions are, and where to fetch them. This is an
example of what this JSON looks like from the `hammer` release from
[https://app.vagrantup.com][2]:

```json
{
"description": "ManageIQ Open-Source Management Platform http://manageiq.org",
"short_description": "ManageIQ Open-Source Management Platform http://manageiq.org",
"name": "manageiq/hammer",
"versions": [
{
"version": "8.6.0",
"status": "active",
"description_html": "<p>hammer-6 release</p>\n",
"description_markdown": "hammer-6 release",
"providers": [
{
"name":"virtualbox",
"url":"https://vagrantcloud.com/manageiq/boxes/hammer/versions/8.6.0/providers/virtualbox.box"
}
]
},
{
"version": "8.5.1",
"status": "active",
"description_html": "<p>hammer-5.1 release</p>\n",
"description_markdown": "hammer-5.1 release",
"providers": [
{
"name": "virtualbox",
"url": "https://vagrantcloud.com/manageiq/boxes/hammer/versions/8.5.1/providers/virtualbox.box"
}
]
},
...
]
}
```

This tool handles converting the list of master releases for vagrant from
[http://releases.manageiq.org/][1] and converts into a metadata form that
`vagrant` can work with. This is required to allow incremented versions from
the master builds that aren't from [vagrantup.com][3].


Requirements
------------

- A recent version of `vagrant`
- Ruby


Usage
-----

To fetch the latest master, just run

```console
$ ./miq_vagrant_master/cli
==> box: Loading metadata for box '/tmp/20190702-13714-1ti54l2'
box: URL: file:///tmp/20190702-13714-1ti54l2
==> box: Adding box 'manageiq/master' (v20190629) for provider: virtualbox
box: Downloading: http://releases.manageiq.org/manageiq-vagrant-master-20190629-b20592c188.box
box: Download redirected to host: XXXXXX-XXXXXX.rXX.cXX.rackcdn.com
==> box: Successfully added box 'manageiq/master' (v20190629) for 'virtualbox'!
```

And it will install a box as the `manageiq/master`. If you want a specific
version, you can either specify a release date:

```console
$ ./miq_vagrant_master/cli --date 20190627
# or
$ ./miq_vagrant_master/cli --version 20190627
==> box: Loading metadata for box '/tmp/20190702-14786-xn9js2'
box: URL: file:///tmp/20190702-14786-xn9js2
==> box: Adding box 'manageiq/master' (v20190627) for provider: virtualbox
box: Downloading: http://releases.manageiq.org/manageiq-vagrant-master-20190627-f06ea8cf96.box
box: Download redirected to host: XXXXXX-XXXXXX.rXX.cXX.rackcdn.com
==> box: Successfully added box 'manageiq/master' (v20190627) for 'virtualbox'!
```

Or a commit SHA:

```console
$ ./miq_vagrant_master/cli --sha f06ea8cf96
# or
$ ./miq_vagrant_master/cli --version f06ea8cf96
==> box: Loading metadata for box '/tmp/20190702-14786-xn9js2'
box: URL: file:///tmp/20190702-14786-xn9js2
==> box: Adding box 'manageiq/master' (v20190627) for provider: virtualbox
box: Downloading: http://releases.manageiq.org/manageiq-vagrant-master-20190627-f06ea8cf96.box
box: Download redirected to host: XXXXXX-XXXXXX.rXX.cXX.rackcdn.com
==> box: Successfully added box 'manageiq/master' (v20190627) for 'virtualbox'!
```

And a proper version of the build will be determined from that.

```console
$ vagrant box list
manageiq/fine (virtualbox, 6.4.0)
manageiq/gaprindashvili (virtualbox, 7.3.0)
manageiq/gaprindashvili (virtualbox, 7.4.0)
manageiq/hammer (virtualbox, 8.1.0-beta2)
manageiq/hammer (virtualbox, 8.5.1)
manageiq/hammer (virtualbox, 8.6.0)
manageiq/master (virtualbox, 20190627)
manageiq/master (virtualbox, 20190629)
```

Note: Because the nightly master builds are not "versioned" like stable
releases, the date is what is used for the version.


[1]: http://releases.manageiq.org/
[2]: https://app.vagrantup.com/manageiq/boxes/hammer.json
[2]: https://app.vagrantup.com
206 changes: 206 additions & 0 deletions miq_vagrant_master/cli
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
#!/usr/bin/env ruby

require 'optparse'

module MIQVagrantMaster
class CLI
# Regexp for parsing the relevant releases from releases.manageiq.org
#
# Defines the following captures:
#
# - FILENAME
# - DATESTAMP
# - SHA
#
RELEASE_REGEXP = /
href="(?<FILENAME>manageiq-vagrant-master- # 1. full filename
(?<DATESTAMP>\d{8})- # 2. date of the build
(?<SHA>[\w\d]*) # 3. SHA of the build
.box)"
/x

# URL for fetching releases
RELEASE_URL = "http://releases.manageiq.org/"

# Shared description for generated metadata.json
DESCRIPTION = "ManageIQ Open-Source Management Platform http://manageiq.org"

# Date of the nightly to help determine version (optional)
attr_reader :date

# SHA of the nightly to help determine version (optional)
attr_reader :sha

# Version (datestamp) of the nightly (optional), defaults to the latest
attr_reader :version

def self.option_parser options
OptionParser.new do |opt|
opt.banner = "Usage: #{File.basename $0} [options]"

opt.separator ""
opt.separator "Download and installs a vagrant box from the nightly"
opt.separator "builds from http://releases.manageiq.org/ and allows"
opt.separator "them to be versioned and remain consistent in a"
opt.separator "Vagrantfile as 'manageiq/master' instead of having to"
opt.separator "create named boxes with versions in them, such as"
opt.separator "'manageiq/master-20190613'"
opt.separator ""
opt.separator ""
opt.separator "Options"

opt.on "-d", "--date=date", "Specifc date to target (sets version)" do |date|
options[:date] = date
end

opt.on "-s", "--sha=SHA", "Specifc SHA to target (sets version)" do |sha|
options[:sha] = sha
end

opt.on "-v", "--version=VERSION", "Version (date) to download (default: latest)" do |version|
options[:version] = version
end

opt.separator ""
opt.separator "Note: `--version` can either be a date or a sha, and"
opt.separator "it will search for either and match whichever it finds"
opt.separator "first."
opt.separator ""

opt.on "--dry-run", "Don't run the `vagrant box add` cmd" do
options[:dry_run] = true
end

opt.on "-h", "--help", "Show this message" do
puts opt
exit
end
end
end

def self.run args = ARGV
new(args).run
end

def initialize args = ARGV
@options = {}

option_parser.parse! args

@date = @options[:date]
@sha = @options[:sha]
@version = @options[:version]
end

# - Builds the metadata_file
# - Determines desired --box-version, or none (latest) if not provided
# - Adds the versioned box to vagrant
def run
metadata_file = build_metadata
install_version = case
when @date
releases.detect(&date_proc)[1]
when @sha
releases.detect(&sha_proc)[1]
when @version
releases.detect(&version_proc)[1]
end

vagrant_cmd = %w[vagrant box add]
vagrant_cmd += ["--box-version", install_version] if install_version
vagrant_cmd << metadata_file.path

if @options[:dry_run]
puts vagrant_cmd.inspect
else
system *vagrant_cmd
end
ensure
metadata_file.unlink if metadata_file
end

private

def option_parser
self.class.option_parser @options
end

# Builds a Tempfile with a local metadata.json that `vagrant` will
# understand when running with `vagrant box add metadata.json`.
#
# Basically gives a readable catalog of what versions are available, where
# "version" is the date of the nightly. Since it "accends" naturally, so
# using that as the version since it doesn't have to follow semver.
#
def build_metadata
require 'json'
require 'tempfile'

metadata = {
"description" => DESCRIPTION,
"short_description" => DESCRIPTION,
"name" => "manageiq/master",
"versions" => map_releases
}

metadata_file = Tempfile.new
metadata_file.write metadata.to_json
metadata_file.close

metadata_file
end

def releases
@releases ||= fetch_releases
end

# Downloads the HTML from http://releases.manageiq.org/ and parses out the
# relevant build links, with DATE and SHA separated:
#
# Example return value:
#
# [
# ["manageiq-vagrant-master-20200101-abcd1234.box", "20200101", "abcd1234"],
# ["manageiq-vagrant-master-20200201-bcde2345.box", "20200201", "bcde2345"],
# ["manageiq-vagrant-master-20200301-cdef3456.box", "20200301", "cdef3456"],
# # ...
# ]
#
def fetch_releases
require "open-uri"

open(RELEASE_URL) { |f| f.read.scan RELEASE_REGEXP }
end

# Maps the releases into a format that vagrant expects for the "versions"
# metadata.json file key.
def map_releases
releases.sort! {|x,y| x[1] <=> y[1] }
.map { |release|
{
"version" => release[1],
"status" => "active",
"description_html" => "<p>#{release[0]}</p>",
"description_markdown" => release[0],
"providers" => [
{"name" => "virtualbox", "url" => "#{RELEASE_URL}#{release[0]}"}
]
}
}
end

def date_proc
proc { |release| release[1] == date }
end

def sha_proc
proc { |release| release[2] == sha }
end

def version_proc
proc { |release| release[1] == version || release[2] == version }
end
end
end

MIQVagrantMaster::CLI.run if __FILE__ == $PROGRAM_NAME