Skip to content

Connects your rails app to the marketplace

License

Notifications You must be signed in to change notification settings

scott/do_addon_connector

Repository files navigation

Unofficial DigitalOcean Marketplace Add-ons Connector

This gem adds all of the required plumbing for your SaaS Rails application to integrate with the new add-ons marketplace at DigitalOcean. It is designed to be flexible and adds integration points, but does not specify how your SaaS creates accounts or handles other specific things. Integrating with the add-ons marketplae involves 4 touch points:

  1. Resources: Account provisioning, deprovisioning, and plan updates,
  2. SSO: Allows DigitalOcean customers to sign into their account from within DigitalOcean
  3. Notifications: Web-hook notifications about specific resources
  4. Configuration Variables: Allows your application to push data back into the customers DigitalOcean interface

Official integration docs here: https://marketplace.digitalocean.com/vendors/saas-api-docs

Requirements

If you use Devise to authenticate Users, this should work mostly out of the box. Each customer of your add-on will be mapped to a single User in your SaaS app. With some customization (see below) you could easily adapt this to work with some other approach, like Account or Tenant mapping.

This connector attempts to be flexible and work with most account/user designs by allowing you to customize what happens after a resource has been provisioned or changed. You can do this through custom logic inserted through Rails Concerns.

Installation

Add to your Gemfile.

gem 'do_addon_connector', git: 'https://github.com/scott/do_addon_connector'
bundle install

Next install and migrate the database, then run the installation script:

bin/rails do_addon_connector:install:migrations
rails db:migrate
bin/rails g do_addon_connector:install

Finally, mount the connector in routes.rb

  mount DoAddonConnector::Engine => '/connectors'

The install script will add an initializer and some Concerns which give you complete flexibility over how your application reacts to a provisioning or SSO request.

Configuration

The initializer do_addon_connector.rb defines configuration values as follows:

# config/initializers/do_addon_connector.rb

DoAddonConnector.setup do |config|
  # 
  # Service Name
  # ======================
  # This is the name of the parent service.  It is used in
  # messages sent back to the user 
  config.service_name = "Application"

  # App Slug
  # ======================
  # This is the slug used by your app.
  config.slug = "acme"

  # Password
  # ======================
  # This is the password assigned to your resource.
  config.password = "password" 

  # Salt
  # ======================
  # This is the salt assigned to your resource.
  config.salt = "sso_salt"
  
  # Secret
  # ======================
  # This is the client secret assigned to your resource
  config.secret = "do_secret".

  # SSO Token Expiration
  # ======================
  # This is how long in seconds before the authentication token 
  # is expired.
  config.token_expires_in = 120

  # Source
  # ======================
  # This represents the source of the user, and can be used
  # to customize your app experience for this type of account.
  config.source = 'digitalocean'

  # SSO Redirect
  # ======================
  # This determines where the user should be taken after a successful SSO.
  # This can also be handled in the `Concern` file.
  config.redirect_to = 'https://scrubl.com/dashboard'

  # Debug
  # ======================
  # Logs additional information and stores SSO tokens for later inspection
  config.debug = false
end

Custom behavior with Concerns

The installation script adds several Concerns to your app. These are used to define app behavior in response to the different actions provided by the provisioning service:

Resource Actions

Resource Provisioning - when the service sends a resource creation request, your app should add an account and/or create a login for the user who has provisioned the app. You can configure how the account/user gets created using: https://github.com/scott/do_addon_connector/blob/master/lib/generators/do_addon_connector/controllers/concerns/resources_controller_extension.rb

Important: The resource creation concern must set an @account instance variable. Failure to do this will cause your provisioning to fail.

After the customer has been added on your app, you can use the customer_extensions concern to add context from metadata and set the resources initial plan subscription. https://github.com/scott/do_addon_connector/blob/master/lib/generators/do_addon_connector/models/concerns/customer_extensions.rb

Plan upgrade/downgrade - The above file also includes an action for upgrading and downgrading plans in response to a request from the provisioning service.

Resource destruction - When DO sends a resource deletion request, your app will need to handle that. You can specify what else will happen in this Concern.

SSO Login request

When a DO user sends a SSO request, you will need to log them into your app. How you authenticate a user is up to your app, but you can use the following to respond to the SSO login request: https://github.com/scott/do_addon_connector/blob/master/lib/generators/do_addon_connector/controllers/concerns/sso_login_extension.rb

Notifications

DigitalOcean marketplace will send notification webhooks to your app when certain events happen. If a customer fails to pay their bill, a webhook indicating this will be sent to your app. Likewise, if the same customer becomes current again, another notification indicating this will be sent.

You can customize how your app behaves in response to any notification within the notifications_concern.

Configuration Variables

Your SaaS can send Key-Value variables back to DigitalOcean where they will be provided to customers within the marketplace UI. This can be useful if you want to communicate an API key, password or URL. To do this, use something like the following:

DoAddonConnetor::Customer.find_by(owner_id: <your-id>).update_config(vars = {"FOO":"BAR})

The owner_id is is the account ID or customer ID on your SaaS.

Contributing

Please submit issues or PRs for bugs or improvement ideas.

License

The gem is available as open source under the terms of the MIT License. Copyright 2022 Scott Miller, Helpy.io, Inc.

Note

This integration is used in production at Helpy.io where it was extracted and turned into a gem. At Helpy we were fortunate enough to gain early access to the add-ons marketplace as a beta partner, and felt it was only appropriate to contribute this work back to accelerate the integration process at other companies.