class EtcdDiscovery::Registrar

Attributes

host[R]
password[R]
service[R]
state[R]
thread[R]
user[R]
watcher[R]

Public Class Methods

new(service, host) click to toggle source
# File lib/etcd-discovery/registrar.rb, line 24
def initialize(service, host)
  @logger = Logger.new($stdout)

  if host.is_a? Hash
    if host.has_key?("uuid")
      host_uuid = "#{SecureRandom.uuid}-#{host["private_hostname"]}"
      host = host.merge("uuid" => host_uuid)
    end
    @host = Host.new host
  elsif host.is_a? EtcdDiscovery::Host
    if host.attributes.has_key?("uuid")
      host.attributes["uuid"] = "#{SecureRandom.uuid}-#{host.attributes["private_hostname"]}"
    end
    @host = host
  else
    raise TypeError, "host should be a Hash or a Etcd::Host, is a #{host.class}"
  end

  # This attribute is later used when instantiating EtcdDiscovery::Service. We want this value to be the content of `service`, always.
  @host.attributes["service_name"] = service

  @service = EtcdDiscovery::Service.new service_params
  @state = :new
  @user = @host.attributes["user"]
  @password = @host.attributes["password"]
end

Public Instance Methods

client() click to toggle source
# File lib/etcd-discovery/registrar.rb, line 111
def client
  config.client
end
config() click to toggle source
# File lib/etcd-discovery/registrar.rb, line 115
def config
  EtcdDiscovery.config
end
host_key() click to toggle source
# File lib/etcd-discovery/registrar.rb, line 119
def host_key
  "/services/#{@service.attributes["name"]}/#{@host.attributes["uuid"]}"
end
register() click to toggle source
# File lib/etcd-discovery/registrar.rb, line 51
def register
  if @state == :started
    @logger.warn "#{@service} is already registered"
    return
  end

  @state = :started

  service_value = @service.to_json

  # Do not start credentials synchro if the service is not public or has no credentials
  if @service.attributes["public"] && (@service.attributes["user"].present? || @service.attributes["password"].present?)
    @watcher = Thread.new do
      @logger.warn "Watcher #{@service.attributes["name"]} started"
      index = 0
      while @state == :started
        begin
          resp = client.watch service_key, index: index
        rescue => e
          @logger.warn "Fail to watch #{service_key}: #{e}, #{e.message}, #{e.class}"
          index = 0
          sleep(config.register_ttl / 2)
          next
        end
        value = JSON.parse resp.node.value
        @user = value["user"]
        @password = value["password"]
        @host.set_credentials user, password
        @service.set_credentials user, password
        index = resp.etcd_index
      end
    end
  end

  client.set(service_key, value: service_value)
  @thread = Thread.new do
    @logger.warn "Register '#{@service}' started"
    while @state == :started
      value = @host.to_json
      begin
        client.set(host_key, value: value, ttl: config.register_ttl)
      rescue => e
        @logger.warn "Fail to set #{service_key}: #{e}, #{e.message}, #{e.class}"
      end
      sleep config.register_renew
    end
    @logger.warn "Register '#{@service}' stopped"
  end

  self
end
service_key() click to toggle source
# File lib/etcd-discovery/registrar.rb, line 123
def service_key
  "/services_infos/#{@service.attributes["name"]}"
end
service_params() click to toggle source
# File lib/etcd-discovery/registrar.rb, line 127
def service_params
  params = {
    "name" => @host.attributes["service_name"],
    "critical" => @host.attributes["critical"],
    "user" => @host.attributes["user"],
    "password" => @host.attributes["password"],
    "public" => @host.attributes["public"]
  }
  params["hostname"] = @host.attributes["name"] if params["public"]
  params["ports"] = @host.attributes["ports"] if params["public"]
  params
end
stop() click to toggle source
# File lib/etcd-discovery/registrar.rb, line 103
def stop
  raise InvalidStateError.new(@state, :started) if @state != :started
  @logger.debug "Set state to :stopped"
  @state = :stopped
  @logger.debug "Delete #{host_key}"
  client.delete(host_key)
end