diff options
Diffstat (limited to 'puppet/modules/couchdb/files')
| -rwxr-xr-x | puppet/modules/couchdb/files/Debian/couchdb | 160 | ||||
| -rw-r--r-- | puppet/modules/couchdb/files/couch-doc-diff | 17 | ||||
| -rw-r--r-- | puppet/modules/couchdb/files/couch-doc-update | 219 | ||||
| -rw-r--r-- | puppet/modules/couchdb/files/local.ini | 84 | 
4 files changed, 480 insertions, 0 deletions
| diff --git a/puppet/modules/couchdb/files/Debian/couchdb b/puppet/modules/couchdb/files/Debian/couchdb new file mode 100755 index 00000000..ccdfe716 --- /dev/null +++ b/puppet/modules/couchdb/files/Debian/couchdb @@ -0,0 +1,160 @@ +#!/bin/sh -e + +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +#   http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +### BEGIN INIT INFO +# Provides:          couchdb +# Required-Start:    $local_fs $remote_fs +# Required-Stop:     $local_fs $remote_fs +# Default-Start:     2 3 4 5 +# Default-Stop:      0 1 6 +# Short-Description: Apache CouchDB init script +# Description:       Apache CouchDB init script for the database server. +### END INIT INFO + +SCRIPT_OK=0 +SCRIPT_ERROR=1 + +DESCRIPTION="database server" +NAME=couchdb +SCRIPT_NAME=`basename $0` +COUCHDB=/usr/bin/couchdb +CONFIGURATION_FILE=/etc/default/couchdb +RUN_DIR=/var/run/couchdb +LSB_LIBRARY=/lib/lsb/init-functions + +if test ! -x $COUCHDB; then +    exit $SCRIPT_ERROR +fi + +if test -r $CONFIGURATION_FILE; then +    . $CONFIGURATION_FILE +fi + +log_daemon_msg () { +    # Dummy function to be replaced by LSB library. + +    echo $@ +} + +log_end_msg () { +    # Dummy function to be replaced by LSB library. + +    if test "$1" != "0"; then +      echo "Error with $DESCRIPTION: $NAME" +    fi +    return $1 +} + +if test -r $LSB_LIBRARY; then +    . $LSB_LIBRARY +fi + +run_command () { +    command="$1" +    if test -n "$COUCHDB_OPTIONS"; then +        command="$command $COUCHDB_OPTIONS" +    fi +    if test -n "$COUCHDB_USER"; then +        if su $COUCHDB_USER -c "$command"; then +            return $SCRIPT_OK +        else +            return $SCRIPT_ERROR +        fi +    else +        if $command; then +            return $SCRIPT_OK +        else +            return $SCRIPT_ERROR +        fi +    fi +} + +start_couchdb () { +    # Start Apache CouchDB as a background process. + +    mkdir -p "$RUN_DIR" +    chown -R "$COUCHDB_USER" "$RUN_DIR" +    command="$COUCHDB -b" +    if test -n "$COUCHDB_STDOUT_FILE"; then +        command="$command -o $COUCHDB_STDOUT_FILE" +    fi +    if test -n "$COUCHDB_STDERR_FILE"; then +        command="$command -e $COUCHDB_STDERR_FILE" +    fi +    if test -n "$COUCHDB_RESPAWN_TIMEOUT"; then +        command="$command -r $COUCHDB_RESPAWN_TIMEOUT" +    fi +    run_command "$command" > /dev/null +} + +stop_couchdb () { +    # Stop the running Apache CouchDB process. + +    run_command "$COUCHDB -d" > /dev/null +    pkill -u couchdb +    # always return true even if no remaining couchdb procs got killed +    /bin/true +} + +display_status () { +    # Display the status of the running Apache CouchDB process. + +    run_command "$COUCHDB -s" +} + +parse_script_option_list () { +    # Parse arguments passed to the script and take appropriate action. + +    case "$1" in +        start) +            log_daemon_msg "Starting $DESCRIPTION" $NAME +            if start_couchdb; then +                log_end_msg $SCRIPT_OK +            else +                log_end_msg $SCRIPT_ERROR +            fi +            ;; +        stop) +            log_daemon_msg "Stopping $DESCRIPTION" $NAME +            if stop_couchdb; then +                log_end_msg $SCRIPT_OK +            else +                log_end_msg $SCRIPT_ERROR +            fi +            ;; +        restart|force-reload) +            log_daemon_msg "Restarting $DESCRIPTION" $NAME +            if stop_couchdb; then +                if start_couchdb; then +                    log_end_msg $SCRIPT_OK +                else +                    log_end_msg $SCRIPT_ERROR +                fi +            else +                log_end_msg $SCRIPT_ERROR +            fi +            ;; +        status) +            display_status +            ;; +        *) +            cat << EOF >&2 +Usage: $SCRIPT_NAME {start|stop|restart|force-reload|status} +EOF +            exit $SCRIPT_ERROR +            ;; +    esac +} + +parse_script_option_list $@ diff --git a/puppet/modules/couchdb/files/couch-doc-diff b/puppet/modules/couchdb/files/couch-doc-diff new file mode 100644 index 00000000..a5907d5e --- /dev/null +++ b/puppet/modules/couchdb/files/couch-doc-diff @@ -0,0 +1,17 @@ +#!/bin/bash + +# Run a diff between a couch document specified as the first parameter +# and the second parameter. +# Diff returns 0 if there is no difference. This way you can tell the data +# is already on the couch. +# Both the couch document and the second paramter will be pretty printed +# before comparison so differences in spaces etc. do not matter. +# All keys starting with an underscore on the couch such as _id and _rev +# will be removed before the comparison - we assume we want to compare +# the real data, not the metadata about the document as we usually do not +# know or care about what the id and revision will be. + +curl -s --netrc-file /etc/couchdb/couchdb.netrc $1 \ + | python -mjson.tool \ + | grep -v '^\s*"_' \ + | diff -w - <(echo $2 | python -mjson.tool) diff --git a/puppet/modules/couchdb/files/couch-doc-update b/puppet/modules/couchdb/files/couch-doc-update new file mode 100644 index 00000000..a137e7ff --- /dev/null +++ b/puppet/modules/couchdb/files/couch-doc-update @@ -0,0 +1,219 @@ +#!/usr/bin/ruby +require 'syslog' + +# +# This script will delete or update the values of a particular couchdb document. The benefit of this little script over +# using a simple curl command for updating a document is this: +# +#   * exit non-zero status if document was not updated. +#   * updates existing documents easily, taking care of the _rev id for you. +#   * if document doesn't exist, it is created +# +# REQUIREMENTS +# +#   gem 'couchrest' +# +# USAGE +# +#   see the ouput of +# +#     couch-doc-update +# +#   the content of <file> will be merged with the data provided. +#   If you only want the file content use --data '{}' +# +# EXAMPLE +# +#   create a new user: +#     couch-doc-update --db _users --id org.couchdb.user:ca_daemon --data '{"type": "user", "name": "ca_daemon", "roles": ["certs"], "password": "sshhhh"}' +# +#   update a user: +#     couch-doc-update --db _users --id org.couchdb.user:ca_daemon --data '{"password":"sssshhh"}' +# +#   To update the _users DB on bigcouch, you must connect to port 5986 instead of the default couchdb port 5984 +# +#   delete a doc: +#     couch-doc-update --delete --db invite_codes --id dfaf0ee65670c16d5a9161dc86f3bff8 +# + +begin; require 'rubygems'; rescue LoadError; end # optionally load rubygems +require 'couchrest' + +def main +  db, id, data, delete = process_options + +  result = if delete +    delete_document(db, id) +  else +    set_document(db, id, data) +  end + +  exit 0 if result['ok'] +  raise StandardError.new(result.inspect) +rescue StandardError => exc +  db_without_password = db.to_s.sub(/:[^\/]*@/, ':PASSWORD_HIDDEN@') +  indent = "       " +  log "ERROR: " + exc.to_s +  log indent + $@[0..4].join("\n#{indent}") +  log indent + "Failed writing to #{db_without_password}/#{id}" +  exit 1 +end + +def log(message) +  $stderr.puts message +  Syslog.open('couch-doc-update') do |logger| +    logger.log(Syslog::LOG_CRIT, message) +  end +end + +def process_options +  # +  # parse options +  # +  host       = nil +  db_name    = nil +  doc_id     = nil +  new_data   = nil +  filename   = nil +  netrc_file = nil +  delete     = false +  loop do +    case ARGV[0] +      when '--host' then ARGV.shift; host     = ARGV.shift +      when '--db'   then ARGV.shift; db_name  = ARGV.shift +      when '--id'   then ARGV.shift; doc_id   = ARGV.shift +      when '--data' then ARGV.shift; new_data = ARGV.shift +      when '--file' then ARGV.shift; filename = ARGV.shift +      when '--netrc-file' then ARGV.shift; netrc_file = ARGV.shift +      when '--delete' then ARGV.shift; delete = true +      when /^-/     then usage("Unknown option: #{ARGV[0].inspect}") +      else break +    end +  end +  usage("Missing required option") unless db_name && doc_id && (new_data || delete) + +  unless delete +    new_data = MultiJson.load(new_data) +    new_data.merge!(read_file(filename)) if filename +  end +  db  = CouchRest.database(connection_string(db_name, host, netrc_file)) +  return db, doc_id, new_data, delete +end + +def read_file(filename) +  data = MultiJson.load( IO.read(filename) ) +  # strip off _id and _rev to avoid conflicts +  data.delete_if {|k,v| k.start_with? '_'} +end + +  # +  # update document +  # +def set_document(db, id, data) +  attempt ||= 1 +  doc = get_document(db, id) +  if doc +    doc.id ||= id +    update_document(db, doc, data) +  else +    create_document(db, id, data) +  end +rescue RestClient::Conflict +  # retry once, reraise if that does not work +  raise if attempt > 1 +  attempt += 1 +  retry +end + +COUCH_RESPONSE_OK = { 'ok' => true } + +# Deletes document, if exists, with retry +def delete_document(db, id) +  attempts ||= 1 +  doc = get_document(db, id) +  if doc +    db.delete_doc(doc) +  else +    COUCH_RESPONSE_OK +  end +rescue RestClient::ExceptionWithResponse => e +  if attempts < 6 && !e.response.nil? && RETRY_CODES.include?(e.response.code) +    attempts += 1 +    sleep 10 +    retry +  else +    raise e +  end +end + +def get_document(db, doc_id) +  begin +    db.get(doc_id) +  rescue RestClient::ResourceNotFound +    nil +  end +end + +# if the response status code is one of these +# then retry instead of failing. +RETRY_CODES = [500, 422].freeze + +def update_document(db, doc, data) +  attempts ||= 1 +  doc.reject! {|k,v| !["_id", "_rev"].include? k} +  doc.merge! data +  db.save_doc(doc) +rescue RestClient::ExceptionWithResponse => e +  if attempts < 6 && !e.response.nil? && RETRY_CODES.include?(e.response.code) +    attempts += 1 +    sleep 10 +    retry +  else +    raise e +  end +end + +def create_document(db, doc_id, data) +  attempts ||= 1 +  data["_id"] = doc_id +  db.save_doc(data) +rescue RestClient::ExceptionWithResponse => e +  if attempts < 6 && !e.response.nil? && RETRY_CODES.include?(e.response.code) +    attempts += 1 +    sleep 10 +    retry +  else +    raise e +  end +end + +def connection_string(database, host, netrc_file = nil) +  protocol  = "http" +  #hostname  = "127.0.0.1" +  port      = "5984" +  username  = "admin" +  password  = "" + +  netrc = File.read(netrc_file || '/etc/couchdb/couchdb.netrc') +  netrc.scan(/\w+ [\w\.]+/).each do |key_value| +    key, value = key_value.split ' ' +    case key +      when "machine"  then host ||= value + ':' + port +      when "login"    then username = value +      when "password" then password = value +    end +  end + +  host ||= '127.0.0.1:5984' + +  "%s://%s:%s@%s/%s" % [protocol, username, password, host, database] +end + +def usage(s) +  $stderr.puts(s) +  $stderr.puts("Usage: #{File.basename($0)} --host <host> --db <db> --id <doc_id> --data <json> [--file <file>] [--netrc-file <netrc-file>]") +  $stderr.puts("       #{File.basename($0)} --host <host> --db <db> --id <doc_id> --delete [--netrc-file <netrc-file>]") +  exit(2) +end + +main() diff --git a/puppet/modules/couchdb/files/local.ini b/puppet/modules/couchdb/files/local.ini new file mode 100644 index 00000000..7365b6c6 --- /dev/null +++ b/puppet/modules/couchdb/files/local.ini @@ -0,0 +1,84 @@ +; CouchDB Configuration Settings + +; Custom settings should be made in this file. They will override settings +; in default.ini, but unlike changes made to default.ini, this file won't be +; overwritten on server upgrade. + +[couchdb] +;max_document_size = 4294967296 ; bytes + +[httpd] +;port = 5984 +;bind_address = 127.0.0.1 +; Options for the MochiWeb HTTP server. +;server_options = [{backlog, 128}, {acceptor_pool_size, 16}] +; For more socket options, consult Erlang's module 'inet' man page. +;socket_options = [{recbuf, 262144}, {sndbuf, 262144}, {nodelay, true}] + +; Uncomment next line to trigger basic-auth popup on unauthorized requests. +;WWW-Authenticate = Basic realm="administrator" + +; Uncomment next line to set the configuration modification whitelist. Only +; whitelisted values may be changed via the /_config URLs. To allow the admin +; to change this value over HTTP, remember to include {httpd,config_whitelist} +; itself. Excluding it from the list would require editing this file to update +; the whitelist. +;config_whitelist = [{httpd,config_whitelist}, {log,level}, {etc,etc}] + +[httpd_global_handlers] +;_google = {couch_httpd_proxy, handle_proxy_req, <<"http://www.google.com">>} + +[couch_httpd_auth] +; If you set this to true, you should also uncomment the WWW-Authenticate line +; above. If you don't configure a WWW-Authenticate header, CouchDB will send +; Basic realm="server" in order to prevent you getting logged out. +; require_valid_user = false + +[log] +;level = debug + +[os_daemons] +; For any commands listed here, CouchDB will attempt to ensure that +; the process remains alive while CouchDB runs as well as shut them +; down when CouchDB exits. +;foo = /path/to/command -with args + +[daemons] +; enable SSL support by uncommenting the following line and supply the PEM's below. +; the default ssl port CouchDB listens on is 6984 +; httpsd = {couch_httpd, start_link, [https]} + +[ssl] +;cert_file = /full/path/to/server_cert.pem +;key_file = /full/path/to/server_key.pem +;password = somepassword +; set to true to validate peer certificates +verify_ssl_certificates = false +; Path to file containing PEM encoded CA certificates (trusted +; certificates used for verifying a peer certificate). May be omitted if +; you do not want to verify the peer. +;cacert_file = /full/path/to/cacertf +; The verification fun (optionnal) if not specidied, the default +; verification fun will be used. +;verify_fun = {Module, VerifyFun} +ssl_certificate_max_depth = 1 +; To enable Virtual Hosts in CouchDB, add a vhost = path directive. All requests to +; the Virual Host will be redirected to the path. In the example below all requests +; to http://example.com/ are redirected to /database. +; If you run CouchDB on a specific port, include the port number in the vhost: +; example.com:5984 = /database + +[vhosts] +;example.com = /database/ + +[update_notification] +;unique notifier name=/full/path/to/exe -with "cmd line arg" + +; To create an admin account uncomment the '[admins]' section below and add a +; line in the format 'username = password'. When you next start CouchDB, it +; will change the password to a hash (so that your passwords don't linger +; around in plain-text files). You can add more admin accounts with more +; 'username = password' lines. Don't forget to restart CouchDB after +; changing this. +[admins] +;admin = mysecretpassword | 
