Skip to content

Instantly share code, notes, and snippets.

@code
Created November 3, 2008 06:24
Show Gist options
  • Save code/21814 to your computer and use it in GitHub Desktop.
Save code/21814 to your computer and use it in GitHub Desktop.
Quick and dirty api for dreamhost uisng mechanize. Add / remove domains, users, and databases.
# File: dreamhost_adapter.rb
# Author: Luke Hubbard
# Gist: http://gist.github.com/gists/21814
# License: MIT
require 'rubygems'
require 'mechanize'
require 'logger'
# Need to monkey patch the CookieJar so it accepts SSL cookies!
module WWW
class Mechanize
class CookieJar
def add(uri, cookie)
# Move this line up, added split
normal_domain = cookie.domain.downcase.split(":").first
return unless uri.host =~ /#{normal_domain}$/i
unless @jar.has_key?(normal_domain)
@jar[normal_domain] = Hash.new
end
@jar[normal_domain][cookie.name] = cookie
cleanup()
cookie
end
end
end
end
# Ugly hack stop random SSL errors
module WWW
class Mechanize
class Chain
class SSLResolver
def handle(ctx, params)
uri = params[:uri]
http_obj = params[:connection]
if uri.scheme == 'https' && ! http_obj.started? and !http_obj.use_ssl # Added last bit
http_obj.use_ssl = true
http_obj.verify_mode = OpenSSL::SSL::VERIFY_NONE
if @ca_file
http_obj.ca_file = @ca_file
http_obj.verify_mode = OpenSSL::SSL::VERIFY_PEER
http_obj.verify_callback = @verify_callback if @verify_callback
end
if @cert && @key
http_obj.cert = OpenSSL::X509::Certificate.new(::File.read(@cert))
http_obj.key = OpenSSL::PKey::RSA.new(::File.read(@key), @pass)
end
end
super
end
end
end
end
end
class DreamhostAdapter < WWW::Mechanize
PANEL_URL = 'https://panel.dreamhost.com:443/index.cgi'
LOGIN_URL = PANEL_URL
LOGOUT_URL = PANEL_URL + '?Nscmd=Nlogout'
ADD_DOMAIN_URL = PANEL_URL + '?tree=domain.manage&current_step=Index&next_step=ShowAddhttp&domain='
DEL_DOMAIN_URL = PANEL_URL + '?tree=domain.manage&current_step=Index&next_step=ShowDestroyDomain&domain='
ADD_USER_URL = PANEL_URL + '?tab=users&subtab=users&current_step=Index&next_step=Add'
LIST_USER_URL = PANEL_URL + '?tree=users.users'
MYSQL_DB_URL = PANEL_URL + '?tree=goodies.mysql&'
attr_accessor :email, :password, :logged_in
def initialize(email, password)
super()
#self.cookie_jar = WWW::Mechanize::CookieJar.new
self.email = email
self.password = password
self.user_agent_alias = 'Mac Mozilla'
self.log = Logger.new(STDOUT, :level=>:debug)
login or raise "Login failed" unless self.logged_in
end
# :domain=>"blah.codegent.org"
# :user=>"codegent"
# :relpath=>"www/apps/blah/current/public"
# :mod_security_on=>true
# :passenger=>true
# :fastcgi=>false
# :www_redir=>"both" "www" "notwww"
# :google_apps=>false
# :gmail=>:false
def add_domain!(options)
options_required!(options, :domain, :relpath)
get(ADD_DOMAIN_URL)
form = page.forms.first
form.domain = options[:domain]
form.relpath = options[:relpath]
unless options[:user].nil?
user_options = form.fields.name('usid').options
# look for a matching user, note we dont require the (on server) part.
option = user_options.detect{|it| it.text =~ /^#{options[:user]} \(on [a-z0-9]+\)$/i }
if option.nil?
user_options.last.select
form.newuser_username = options[:user]
else
option.select
end
end
populate_checkboxes_from_options(form.checkboxes, options)
populate_radiobuttons_from_options(form.radiobuttons, options)
submit(form, form.buttons.first)
check_for_success
end
def delete_domain!(options)
options_required!(options, :domain)
get(DEL_DOMAIN_URL+options[:domain])
form = page.forms.first
form.checkboxes.name('confirm').check
submit(form)
check_for_success
end
# :type=>'shell'
# :shell=>'bash'
# :user=>'slice201'
# :lockdown_homedir=>true
# :password=>"icanhazslice"
# :disable_ftp=>true
# :sa_chk=>true enable cpu check
# :notify_disk=>true
# :quote_chk=>true limit disk
# :hard_quota=>"1000"
def add_user!(options)
options_required!(options, :type, :user, :password)
options[:gecos] ||= " "
get(ADD_USER_URL)
form = page.forms.first
form.user = options[:user]
form.pw1 = options[:password]
form.pw2 = options[:password]
form.gecos = options[:gecos]
unless options[:shell].nil?
shell_options = form.fields.name('shell').options
# look for a matching shell, note we dont require path prefix.
option = shell_options.detect{|it| it.text =~ /\/#{options[:shell]}/i }
option.select unless option.nil?
end
populate_checkboxes_from_options(form.checkboxes, options)
populate_radiobuttons_from_options(form.radiobuttons, options)
submit(form)
check_for_success
end
def delete_user!(options)
options_required!(options, :user)
get(LIST_USER_URL)
link = page.search('td a').select{|it| it.inner_text.strip =~ /Delete/ }.reject{|it| it[:href] =~ /withDomain/ }.detect{|it| it[:href] =~ /user=([a-z0-9_-]+)\&/ and $1.eql?(options[:user]) }
return false unless link
click link
form = page.forms.first
form.checkboxes.name('confirm').check
submit(form)
check_for_success
end
def add_mysql!(options)
# Needs to use new user for each db, and default hostname
options_required!(options, :dbname, :user, :password)
get(MYSQL_DB_URL)
form = page.forms.last
form.fields.name('old_username').options.last.select
form.dbname = options[:dbname]
form.username = options[:user]
form.pw1 = options[:password]
form.pw2 = options[:password]
submit(form)
check_for_success
end
def add_mysql!(options)
# Needs to use new user for each db, and default hostname
options_required!(options, :dbname, :user, :password)
get(MYSQL_DB_URL)
form = page.forms.last
user_options = form.fields.name('old_username').options
option = user_options.detect{|it| it.value.eql?(options[:user]) }
if option.nil?
user_options.last.select
form.username = options[:user]
else
option.select
end
form.dbname = options[:dbname]
form.pw1 = options[:password]
form.pw2 = options[:password]
#raise form.inspect
submit(form)
check_for_success
end
def options_required!(options, *required)
required.each { |option| raise "Missing required option: #{option}" unless options.has_key? option }
end
def populate_checkboxes_from_options(checkboxes, options)
checkboxes.each do |checkbox|
checked = options[checkbox.name.to_sym]
if checked == true
checkbox.check
elsif checkbox == false
checkbox.uncheck
end
end
end
def populate_radiobuttons_from_options(radiobuttons, options)
radiobuttons.each do |radio|
next if (value = options[radio.name.to_sym]).nil?
radio.check if radio.value.eql?(value)
end
end
def check_for_success
match = page.search('.successbox_head')
raise "Didn't return success" unless match.size > 0
match.text.strip.eql?("Success!")
rescue
log.error "Unexpected response: #{$!}"
log.debug page.inspect
log.debug page.body.inspect
false
end
def click_link(pattern)
pattern = pattern.is_a?(Regexp) ? pattern : /#{pattern}/i
click page.links.text(pattern).first
end
private
def login(email=@email, password=@password)
tries = 0
@logged_in = begin
get(LOGIN_URL)
# Fill out the login form
form = page.forms.first
form.username = email
form.password = password
submit(form, form.buttons.first)
# Check we have a logout link
!page.links.text(/Logout/).first.nil?
# If something random goes wrong
rescue
# Try 3 times before giving up
tries += 1
retry unless tries > 3
raise $!
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment