README.md in convox_installer-1.0.1 vs README.md in convox_installer-1.0.2
- old
+ new
@@ -1,23 +1,290 @@
# Convox Installer
+A Ruby gem that makes it easier to build a Convox installation script. This is like Chef/Ansible/Terraform for your initial Convox setup.
+
+## NOTE: This software is an alpha version
+
+Please note that the code quality is not very good, and the test coverage needs to be improved. However, I've successfully set up a number of test and production deployments using this gem, and everything seems to work very well. The library also facilitates idempotency and crash-resistance, so you can easily re-run your installation script if something goes wrong.
+
+## Features
+
+* Idempotent. If this script crashes, you can restart it and it will pick up
+ where it left off. Every step looks up the existing state, and only makes a change
+ if things are not yet set up (or out of sync).
+* Ensures that the `convox` and `aws` CLI tools are installed
+* Wraps the `convox` CLI and parses JSON output from API calls
+* Add n Docker Repository (e.g. ECR registry)
+* Set up an S3 bucket with an optional CORS policy
+
+## Introduction
+
[Convox](https://convox.com/) is an awesome open source PaaS, which is like Heroku for your own AWS account. [`convox/rack`](https://github.com/convox/rack) is completely open source and free to use, but you can also sign up for a free or paid account to use the hosted service on convox.com.
`convox_installer` is a Ruby gem that makes it much easier to build an installation script for `convox/rack` (the open source PaaS). The Convox CLI is awesome, but it's missing a nice way to script a full deployment. I originally wrote a bash script that made API calls and used [`jq`](https://stedolan.github.io/jq/) and `sed`, but this was very error-prone and it did not have good cross-platform support.
I've rewritten this installation script in Ruby, which provides very good cross-platform support, and also allows me to write tests.
-# Usage
+## Usage
-You should create a new git repo for your own installation script, and then use the provided classes and methods to build your own installation workflow. You must also include a `convox.yml`.
+Create a new Ruby file (e.g. `install.rb`), and use `bundler/inline` to install and require the `convox_installer` gem. Your install script should start like this:
-You can see an example in [`examples/full_installation.rb`](./examples/full_installation.rb).
-(This Ruby file uses `bundler/inline`, so it will download and install the `convox_installer` gem before running the script.)
+```ruby
+#!/usr/bin/env ruby
+require 'bundler/inline'
-# Config
+gemfile do
+ source 'https://rubygems.org'
+ gem 'convox_installer'
+end
+require "convox_installer"
+include ConvoxInstaller
+```
+
+Including the `include ConvoxInstaller` gives you some Ruby methods that you can call to construct an installation workflow. See the "`ConvoxInstaller` DSL" section below.
+
+You should create a new git repo for your own installation script, and then use the provided classes and methods to build your own installation workflow. You must also include a `convox.yml` (or a `convox.example.yml`).
+
+You can see a complete example in [`examples/full_installation.rb`](./examples/full_installation.rb).
+
+
+## Config
+
Config is loaded from ENV vars, or from saved JSON data at
-`~/.convox/installer_config`.
+`~/.convox/installer_config`. The script will save all of the user's responses into `~/.convox/installer_config`.
-### License
+## Customize the Config Prompts
+
+You can set your own config prompts in your own installation script, by setting a `@prompts` instance variable. You can extend the default config prompts like this:
+
+```ruby
+@prompts = ConvoxInstaller::Config::DEFAULT_PROMPTS + [
+ {
+ section: "Docker Authentication",
+ info: "You should have received authentication details for the Docker Registry\n" \
+ "via email. If not, please contact support@example.com",
+ },
+ {
+ key: :docker_registry_url,
+ title: "Docker Registry URL",
+ value: "1234567890.dkr.ecr.us-east-1.amazonaws.com",
+ },
+ {
+ key: :docker_registry_username,
+ title: "Docker Registry Username",
+ },
+ {
+ key: :docker_registry_password,
+ title: "Docker Registry Password",
+ }
+]
+```
+
+## Prompt API:
+
+The `@prompts` variable must be an array of hashes. There are two kinds of hashes:
+
+#### Section Heading
+
+Shows a heading and optional details.
+
+```ruby
+{
+ section: "The heading for this config section",
+ info: "Description about this config section"
+}
+```
+
+#### Config Prompt
+
+* A config prompt with a default value:
+
+```ruby
+{
+ key: :config_key_name,
+ title: "Title to show in the user prompt / config summary",
+ prompt: "Question to show the user",
+ default: "default value",
+}
+```
+
+* Set a value from a `Proc`, and don't prompt the user:
+
+```ruby
+ {
+ key: :config_key_name,
+ title: "Title to show in the config summary",
+ value: -> () { "string-with-random-suffix-#{SecureRandom.hex(4)}" },
+ }
+```
+
+* Set a value, and hide this setting from the user (even in the summary):
+
+```ruby
+ {
+ key: :config_key_name,
+ value: "Config Value",
+ hidden: true,
+ },
+```
+
+
+## `ConvoxInstaller` DSL
+
+#### `ensure_requirements!`
+
+Makes sure that the `convox` and `aws` CLI tools are installed on this system. If not, shows installation instructions and exits.
+
+#### `prompt_for_config`
+
+Loads config from ENV vars, or from saved config at `~/.convox/installer_config`.
+If any config settings are missing, it prompts the user for input. Finally, it shows a summary of the config, and asks the user if they want to proceed with the installation. If the user enters `y` (or `yes`), the `prompt_for_config` method completes. If they enter `n` (or `no`), we loop over every setting and let them press "enter" to keep the current value, or provide a new value to correct any mistakes.
+
+#### `backup_convox_host_and_rack`
+
+If there are any existing files at `~/.convox/host` or `~/.convox/rack`, this method moves these to `~/.convox/host.bak` and `~/.convox/rack.bak`.
+
+#### `install_convox`
+
+* **Required Config:** `aws_region`, `aws_access_key_id`, `aws_secret_access_key`,
+ `stack_name`, `instance_type`
+
+Runs `convox rack install ...`. Has some validations to ensure that all required settings are present.
+
+#### `validate_convox_auth_and_set_host!`
+
+After running `install_convox`, call this method to ensure that the the `~/.convox/auth` file has been updated with the correct details (checks the rack name and AWS region.) Then it sets the rack host in `~/.convox/host` (if not already set.)
+
+#### `validate_convox_rack!`
+
+Calls `convox api get /system` to get the Rack details, then makes sure that everything is correct.
+
+#### `convox_rack_data`
+
+Returns a Ruby hash with all convox rack data.
+
+#### `create_convox_app!`
+
+* **Required Config:** `convox_app_name`
+
+Checks if the app already exists. If not, calls `convox apps create ... --wait` to create a new app. Then waits for the app to be ready. (Avoids an occasional race condition.)
+
+
+#### `set_default_app_for_directory!`
+
+Writes the app name into `./.convox/app` (in the current directory.) The `convox` CLI reads this file, so you don't need to specify the `--app` flag for future commands.
+
+
+#### `create_s3_bucket!`
+
+* **Required Config:** `s3_bucket_name`
+
+Creates an S3 bucket from the `:s3_bucket_name` config setting. This is not a default setting, so you can add something like this to your custom `@prompts`:
+
+```ruby
+ {
+ key: :s3_bucket_name,
+ title: "S3 Bucket for uploads",
+ value: -> () { "yourapp-uploads-#{SecureRandom.hex(4)}" },
+ }
+```
+
+The `:value` `Proc` will generate a bucket name with a random suffix. (Avoids conflicts when you are setting up multiple deployments for your app.)
+
+`create_s3_bucket!` will also call `set_s3_bucket_cors_policy` automatically, so you don't need to call this manually.
+
+#### `set_s3_bucket_cors_policy`
+
+* **Required Config:** `s3_bucket_name`
+
+Set up a CORS policy for your S3 bucket. (`:s3_bucket_name`)
+
+*Note: If the `:s3_bucket_cors_policy` setting is not provided, then this method does nothing.*
+
+You should set `:s3_bucket_cors_policy` to a JSON string. Here's how I set this up in my own `install.rb` script:
+
+```ruby
+S3_BUCKET_CORS_POLICY = <<-JSON
+{
+ "CORSRules": [
+ {
+ "AllowedOrigins": ["*"],
+ "AllowedHeaders": ["Authorization", "cache-control", "x-requested-with"],
+ "AllowedMethods": ["PUT", "POST", "GET"],
+ "MaxAgeSeconds": 3000
+ }
+ ]
+}
+JSON
+
+@prompts = [
+ {
+ key: :s3_bucket_cors_policy,
+ value: S3_BUCKET_CORS_POLICY,
+ hidden: true,
+ }
+]
+```
+
+
+#### `s3_bucket_details`
+
+* **Required Config:** `s3_bucket_name`
+
+Get the S3 bucket details for `s3_bucket_name`. Parses the URL and returns a hash:
+
+```ruby
+{
+ access_key_id: "AWS Access Key ID",
+ secret_access_key: "AWS Secret Access Key",
+ name: "Full S3 Bucket Name (includes the rack/app)",
+}
+```
+
+I use these S3 bucket details to set env variables for my app. (`convox env set ...`)
+
+
+#### `add_docker_registry!`
+
+* **Required Config:** `docker_registry_url`, `docker_registry_username`, `docker_registry_password`
+
+Checks the list of registries to see if `docker_registry_url` has already been added. If not, runs `convox registries add ...` to add a new Docker registry (e.g. Docker Hub, ECR).
+
+#### `default_service_domain_name`
+
+* **Required Config:** `convox_app_name`, `default_service`
+
+Parses the rack router ELB name and region, and returns the default `convox.site` domain for your default service. (You can visit this URL in the browser to access your app.)
+
+Example: `myapp-web.rackname-Route-ABCDFE123456-123456789.us-west-2.convox.site`
+
+Set a default service in your config prompts (e.g. `web`):
+
+```ruby
+@prompts = [
+ # ...
+ {
+ key: :default_service,
+ title: "Default Convox Service (for domain)",
+ value: "web",
+ hidden: true,
+ }
+]
+```
+
+> (This hidden setting isn't visible to the user.)
+
+#### `run_convox_command!(cmd)`
+
+Runs a `convox` CLI command, and shows all output in the terminal. Crashes the script with an error if the `convox` command has a non-zero exit code.
+
+If you want to run `convox env set MYVAR=value`, then you would call:
+
+```ruby
+run_convox_command! 'env set MYVAR=value'
+```
+
+
+## License
[MIT](./LICENSE)