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
Install
gem install lumberg
Usage
Create a server object and connect to WHM using your host and hash:
require 'lumberg'
server = Lumberg::Whm::Server.new(
host: WHM_HOST,
hash: WHM_HASH
)
If you are using HTTP Basic Authentication with a username/password:
server = Lumberg::Whm::Server.new(
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:
account = server.account
result = account.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: "bob.com",
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.account.create(
username: 'newuser',
domain: 'newuser.com',
password: 'password'
)
if result[:success]
p result[:message]
end
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 'newuser.com'
Suspending an account is simple and the reason for suspension is optional.
result = server.account.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.account.remove(username: 'newuser')
p result[:message]
newuser account 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.account.create(
username: 'rtest',
domain: 'resellerexample.com',
password: 'password'
)
if result[:success]
result = server.reseller.create(username: 'rtest', makeowner: true)
p "created reseller rtest" if result[:success]
end
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 = Lumberg::Cpanel::Email.new(
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 my-forwarder@domain.com to
# dest@other-domain.com
email.add_forwarder(
domain: "domain.com",
email: "my-forwarder",
fwdopt: "fwd",
fwdemail: "dest@other-domain.com"
)
Contributing
Extending Lumberg::Cpanel
-
Find a cPanel API module that isn't already covered. See cPanel API documentation for a full list of available API modules.
-
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 fromlib/lumberg/cpanel.rb
. -
Define a class that inherits from
Lumberg::Cpanel::Base
:# 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:module Lumberg module Cpanel class SslInfo def self.api_module; "SSLInfo"; end end end end
-
Fill in the methods.
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_HOST=my-cpanel-server.com 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
Copyright (c) 2015-2016 Pressed, LLC. See LICENSE for details.