Lumberg Lumberg Build Status

Lumberg logo

Ruby library for the WHM & cPanel API. It is currently what we consider to be beta-ish. Please report any issues you find. :)


Confirmed to work with ruby 2.1.3, 2.2.0, 2.3.1 and JRuby 1.9 mode.

cPanel Version Targets

  • cPanel 11.4x: v2.0.0
  • cPanel 11.3x: v2.0.0.pre10
  • cPanel 11.2x: v1.1.1


gem install lumberg


Create a server object and connect to WHM using your host and hash:

require 'lumberg'
server =
  host: WHM_HOST,
  hash: WHM_HASH

If you are using HTTP Basic Authentication with a username/password:

server =
  host:       WHM_HOST,
  user:       USERNAME,
  hash:       'my_password',
  basic_auth: true

You can access the modules of WHM by calling server.<module>. For example, server.account or server.dns. Here are the currently supported modules:

  • Account
  • DNS
  • Reseller

Here's how to get a list of accounts:

 = server.
result  = .list

Most responses will return success and a message

p "Returned #{result[:success]} with message: #{result[:message]}"

Returned true with message: Ok

You can grab the data you need from the results hash

num_accounts = result[:params][:acct].size
p "There are #{num_accounts} accounts"

There are 6 accounts

Here's an example of what the returned data looks like for a single account

pp result[:params][:acct].first

  startdate:      false,
  plan:           "default",
  suspended:      false,
  theme:          "x3",
  shell:          "/usr/local/cpanel/bin/jailshell",
  maxpop:         "unlimited",
  maxlst:         "unlimited",
  maxaddons:      "*unknown*",
  suspendtime:    nil,
  ip:             false,
  maxsub:         "unlimited",
  domain:         "",
  maxsql:         "unlimited",
  partition:      "home",
  maxftp:         "unlimited",
  user:           "bob",
  suspendreason:  "not suspended",
  unix_startdate: false,
  diskused:       false,
  maxparked:      "*unknown*",
  email:          "*unknown*",
  disklimit:      "unlimited",
  owner:          "root"

Account Example

Creating a new account requires only a username, domain, and password.

result = server..create(
  username: 'newuser',
  domain:   '',
  password: 'password'

if result[:success]
  p result[:message]

Account Creation Ok

You can list all accounts or search for a specific account.

result = server.account.list(search: 'new', searchtype: 'user')
acct   = result[:params][:acct].first
p "Found user '#{acct[:user]}' with domain '#{acct[:domain]}'"

Found user 'newuser' with domain ''

Suspending an account is simple and the reason for suspension is optional.

result = server..suspend(username: 'newuser', reason: 'bad user')
p "user was suspended successfully" if result[:success]

user was suspended successfully

We can look at the account list again to see the reason for the user's suspension.

result = server.account.list(search: 'new', searchtype: 'user')
acct   = result[:params][:acct].first
p "user '#{acct[:user]}' was suspended with reason '#{acct[:suspendreason]}'"

user 'newuser' was suspended with reason 'bad user'

Finally, we remove the user and delete their account.

result = server..remove(username: 'newuser')
p result[:message]

newuser  removed

Reseller Example

Creating a reseller works by changing the status of an existing user account, so first we create a user account and then we can create that user as a reseller.

result = server..create(
  username: 'rtest',
  domain:   '',
  password: 'password'

if result[:success]
  result = server.reseller.create(username: 'rtest', makeowner: true)
  p "created reseller rtest" if result[:success]

created reseller rtest

You can get a list of all of the reseller accounts easily.

result = server.reseller.list
p result[:params][:resellers].inspect

["samir", "rtest"]

Suspending a reseller is pretty straightforward. It's optional to provide a reason for the suspension.

result = server.reseller.suspend(username: 'rtest', reason: 'bad user')
p "reseller was suspended successfully" if result[:success]

user was suspended successfully

Deleting the reseller removes the reseller status from the user account. To also delete the user account, set the :terminatereseller argument.

result = server.reseller.terminate(reseller: 'rtest', terminatereseller: true)
p result[:message]

Account Terminations Complete

Accessing cPanel API

cPanel API interface is provided by the Lumberg::Cpanel module. Classes within the module correspond to cPanel API modules. cPanel API module coverage is currently incomplete and we're seeking contributions. Check out Extending Lumberg::Cpanel for details on how you can help.

Email example

# Create an interface object for cPanel API Email module
email =
  server:       server,  # An instance of Lumberg::Server
  api_username: "jerry"  # User whose cPanel we'll be interacting with

# Get a list of email accounts
email.accounts[:params][:data] #=> Array of info hashes for each email account

# Add an email forwarder to forward mail for to
  domain:   "",
  email:    "my-forwarder",
  fwdopt:   "fwd",
  fwdemail: ""


Extending Lumberg::Cpanel

  1. Find a cPanel API module that isn't already covered. See cPanel API documentation for a full list of available API modules.

  2. Create a file (underscore style) in lib/lumberg/cpanel/ named after the cPanel API module you're working on. If the cPanel API module is "LangMods" name the file "lang_mods.rb". You'll define your class here. require this file from lib/lumberg/cpanel.rb.

  3. Define a class that inherits from Lumberg::Cpanel::Base: ```ruby

    Create a class for (fictional) "SomeModule" API module

    module Lumberg module Cpanel class SomeModule < Base end end end The cPanel API module name is normally inferred from the class name, e.g., if the class name is `Email` the cPanel "Email" API module will be used. If the cPanel API module you're working with doesn't match up with Ruby class naming convention, override the `::api_module` class method: ruby module Lumberg module Cpanel class SslInfo def self.api_module; "SSLInfo"; end end end end ```

  4. Fill in the methods. ruby module Lumberg module Cpanel class Branding # Public: Get URL locations for specific sprites. # # options - Hash options for API call params (default: {}): # :img - String branding object label for the image you want to # retrieve. # :imgtype - String branding image type you want to retrieve, e.g., # "icon" or "heading". # :method - String specification for returned value options. # Acceptable values are: "only_filetype_gif", # "skip_filetype_gif", "snap_to_smallest_width", and # "scale_60percent". # :subtype - String branding image subtype, e.g., "img", "bg", # "compleximg". # :image - String parameter allows you to force appropriate # output by setting it to "heading" (optional). # :skipgroups - String parameter allows you to specify whether or not # to include "img" values that begin with "group_" in # the output. "1" indicates that you wish to skip "img" # values that begin with "group_" (optional). # # Returns Hash API response. def list_sprites(options = {}) perform_request({ api_function: "spritelist" }.merge(options)) end end end end

    • In many cases, you'll name your methods to match up with the documented cPanel API methods. However, the documented method names are sometimes a bit lengthy, confusing, or otherwise unwieldy; feel free to give your corresponding method an improved name.
    • Use TomDoc documentation for your methods. Be sure to document all required and optional parameters from the cPanel API documentation.
    • All methods should take an options arg that defaults to {}. These options should be merged onto the options passed to

      perform_request to allow overriding of :api_username or

      other parameters.

Sanitizing VCR cassettes

All HTTP interactions are recorded using VCR and FakeWeb. Please be sure to remove sensitive data from your cassettes. A Rake task is provided for this purpose: WHM_HASH=$(cat my-access-hash) bundle exec rake sanitize_cassettes Once you've sanitized your cassettes, manually verify that there's no sensitive information still present (check URLs, authorization params, etc.).

Note on Patches/Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so we don't break it in a future version unintentionally.
  • Commit, do not mess with Rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself we can ignore when we pull)
  • Send us a pull request. Bonus points for topic branches.


Copyright (c) 2015-2016 WWWH, LLC. See LICENSE for details.