RabbitMQ consumer and publisher (Bunny/Ruby)

Tagged amqp, bunny, rabbitmq, ruby  Languages bash, ruby

Create consumer.rb:

require 'bunny'
bunny = Bunny.new(ENV.fetch('AMQP_URL'))
at_exit { bunny.stop }
channel = bunny.create_channel
exchange = channel.topic(ENV.fetch('EXCHANGE'), durable: true, passive: true)
queue = channel.queue(ENV.fetch('QUEUE'), durable: true, passive: true)
queue.subscribe(manual_ack: true, block: true) do |delivery_info, _metadata, payload|
  puts "==============="
  puts payload
  puts "==============="
  channel.acknowledge(delivery_info.delivery_tag, false)

Start consumer:

$ EXCHANGE=cnn QUEUE=news AMQP_URL=amqp://username:password@localhost:5672 ruby consumer.rb

Create publisher.rb:

require "bunny"

class Publisher
  def self.initialize(amqp_url, exchange:)
    @@bunny = Bunny.new(amqp_url)
    @@channel = @@bunny.create_channel
    # 'passive = true' means exchange already exists
    @@exchange = @@bunny.channel.topic(exchange, passive: true)
    at_exit { @@bunny.stop }

  def self.send(message, queue:)
    @@exchange.publish(message, routing_key: queue)

queue = ENV.fetch('QUEUE')
Publisher.initialize(ENV.fetch('AMQP_URL'), exchange: ENV.fetch('EXCHANGE'))
Publisher.send('Ruby is the best programming language', queue: queue)
Publisher.send('Top 10 silver-bullet solutions in Java', queue: queue)

Start publisher.rb:

$ EXCHANGE=cnn QUEUE=news AMQP_URL=amqp://username:password@localhost:5672 ruby publisher.rb

Search and replace file contents and file names

Tagged bash, find, replace, search  Languages bash

Search and replace file contents and file names

Note that all changes must be commited to git before running the command:

git grep -l 'observation' | xargs sed -i '' -e 's/observation/condition/g'

Search and replace of file names

find . -name '*observation*' -exec bash -c 'mv $0 ${0/observation/condition}' {} \;

View Presenters Pattern in Rails

Tagged pattern, presenters, rails, presenter  Languages html, ruby

View (app/views/episodes/show.slim):

- ep = EpisodePresenter

  li = ep.name(@episode)
  li = ep.producer_name(@episode)
  li = ep.director_name(@episode)
  li = ep.link_to(@episode, view: self)

BasePresenter (app/presenters/base_presenter.rb):

class BasePresenter
  # Delegate methods to model
  def self.method_missing(method, *args, &block)
    model = args.shift
    if model && model.respond_to?(method)
      model.send(method, *args, &block)
      raise NoMethodError, method

Presenter (app/views/presenters/episode_presenters.rb):

class EpisodePresenter < BasePresenter
  # NOTE: method missing delegates to the model, so no need to define this
  # def self.name(episode)
  #   episode.name
  # end
  def self.producer_name(episode)
    "#{episode.producer.first_name} #{episode.producer.last_name}"

  def self.director_name(episode)
    "#{episode.director.first_name} #{episode.director.last_name}"
  # NOTE: Rails helpers can be accessed through the view, if needed.
  def self.link_to(episode, view:, classes: '', text: nil)
    attrs = {
      href: view.episode_path(episode),
      class: classes
    view.content_tag :a, attrs do
      text.presence || 'View'

How to view the client certificates accepted by a website

Tagged ca, certificates, client certificate, openssl, ssl  Languages bash

To view a list of acceptable client certificates, execute:

$ openssl s_client -connect golang.org:443

The output is a list of acceptable CA names:

Acceptable client certificate CA names
/C=FI/ST=Finland/O=Vaestorekisterikeskus CA/OU=XYZ/CN=ÅÄÖ

or, if no client certificates are accepted:

No client certificate CA names sent

To log client certificate information with haproxy:

  bind *:443 ssl crt xyz.com.pem ca-file vrk-ca.pem verify optional crt-ignore-err all crl-file vrk-revocation-list.pem
  # See https://www.haproxy.com/blog/ssl-client-certificate-information-in-http-headers-and-logs/
  http-request set-header X-SSL                  %[ssl_fc]
  http-request set-header X-SSL-Client-Verify    %[ssl_c_verify]
  http-request set-header X-SSL-Client-DN        %{+Q}[ssl_c_s_dn]
  http-request set-header X-SSL-Client-CN        %{+Q}[ssl_c_s_dn(cn)]
  http-request set-header X-SSL-Issuer           %{+Q}[ssl_c_i_dn]
  http-request set-header X-SSL-Client-NotBefore %{+Q}[ssl_c_notbefore]
  http-request set-header X-SSL-Client-NotAfter  %{+Q}[ssl_c_notafter]

  log-format "%ci:%cp [%t] %ft %b/%s %Tq/%Tw/%Tc/%Tr/%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs {%[ssl_c_verify],%{+Q}[ssl_c_s_dn],%{+Q}[ssl_c_i_dn]} %{+Q}r"

Also see https://tools.ietf.org/html/rfc5246#page-53

How to start a bash shell in Docker

Tagged bash, docker, shell  Languages bash

To start a bash shell in an already running container:

docker exec -it <container id/name> bash

To start a bash shell using an image of a container that is not running:

docker run -i -t --entrypoint /bin/bash <image id>

How read process exit code in Golang

Tagged code, exit, status  Languages go

This function returns true if the nz command returns exit code 0:

package main

import (

// IsPortOpen returns a boolean that indicates whether a port is open or closed.
func IsPortOpen(host string, port int) bool {
    args := []string{"-z", host, strconv.Itoa(port), "-G", "5"}
    cmd := exec.Command("/usr/bin/nc", args...)
    _, err := cmd.Output()
    if werr, ok := err.(*exec.ExitError); ok {
        if s := werr.Error(); s != "0" {
            return false
    return true

bcrypt example in Golang

Tagged bcrypt, golang  Languages go
package main

import (

// NOTE: You need to escape the dollar signs in the hash with \
// HASH="xxx" PASSWORD=xxx go run main.go
func main() {
    hash, ok := os.LookupEnv("HASH")
    if !ok {
        log.Fatal("The HASH environment variable is not set")
    password, ok := os.LookupEnv("PASSWORD")
    if !ok {
        log.Fatal("The PASSWORD environment variable is not set")
    if isMatch(password, hash) {
        log.Printf("Match '%s' == '%s'", hash, password)
    } else {
        log.Printf("Mismatch '%s' != '%s'", hash, password)

func isMatch(password string, hash string) bool {
    err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
    return err == nil

For loop in Postgres

Tagged for, loop, postgres  Languages sql
    row record;
    FOR row IN SELECT tablename FROM pg_tables WHERE schemaname = 'public'
        EXECUTE 'ALTER TABLE public.' || quote_ident(row.tablename) || ' SET SCHEMA <new schema>;';