Class: SnapEbs::Plugin::MongoPlugin

Inherits:
SnapEbs::Plugin show all
Defined in:
lib/plugins/mongo_plugin.rb

Constant Summary collapse

WIRED_TIGER_KEY =
'wiredTiger'

Instance Attribute Summary collapse

Attributes inherited from SnapEbs::Plugin

#logger, #options

Instance Method Summary collapse

Methods inherited from SnapEbs::Plugin

#carefully, #collect_options, inherited, registered_plugins

Instance Attribute Details

#clientObject

Returns the value of attribute client.



4
5
6
# File 'lib/plugins/mongo_plugin.rb', line 4

def client
  @client
end

Instance Method Details

#afterObject



67
68
69
70
71
72
73
# File 'lib/plugins/mongo_plugin.rb', line 67

def after
  unlock_or_start_mongo

  if carefully('check that mongo is still accessible') { client.command(serverStatus: 1).first }
    logger.info "Received status from mongo, everything appears to be ok"
  end
end

#beforeObject



53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/plugins/mongo_plugin.rb', line 53

def before
  require 'mongo'
  Mongo::Logger.logger = logger
  return unless safe_to_operate?

  if wired_tiger?
    logger.info "Wired Tiger storage engine detected"
    carefully('stop mongo') { stop_mongo } if options.shutdown
  else
    logger.info "MMAPv1 storage engine detected"
    carefully('lock mongo') { lock_mongo }
  end
end

#client_optionsObject



41
42
43
44
45
46
47
48
49
50
51
# File 'lib/plugins/mongo_plugin.rb', line 41

def client_options
  {
    connect: :direct,
    user: options.user,
    password: options.password,
    server_selection_timeout: options.server_selection_timeout.to_i,
    wait_queue_timeout: options.wait_queue_timeout.to_i,
    connection_timeout: options.connection_timeout.to_i,
    socket_timeout: options.socket_timeout.to_i
  }
end

#default_optionsObject



22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/plugins/mongo_plugin.rb', line 22

def default_options
  {
    shutdown: false,
    command: "service mongod start",
    retry: 720,
    interval: 5,
    port: '27017',
    host: 'localhost',
    server_selection_timeout: 30,
    wait_queue_timeout: 1,
    connection_timeout: 5,
    socket_timeout: 5
  }
end

#defined_optionsObject



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/plugins/mongo_plugin.rb', line 5

def defined_options
  {
    shutdown: 'Shutdown mongodb server (this is required if your data and journal are on different volumes',
    command: 'Command to start mongodb if the server must be shut down (i.e. multi-volume Wired Tiger)',
    retry: 'How many times to retry starting or unlocking mongodb (default: 720)',
    interval: 'Interval (in seconds) to wait when retrying (default: 5)',
    user: 'Mongo user',
    password: 'Mongo password',
    port: 'Mongo port',
    host: 'Mongo host',
    server_selection_timeout: 'Timeout in seconds while choosing a server to connect to (default 30)',
    wait_queue_timeout: 'Timeout in seconds while waiting for a connection in the pool (default 1)',
    connection_timeout: 'Timeout in seconds to wait for a socket to connect (default 5)',
    socket_timeout: 'Timeout in seconds to wait for an operation to execute on a socket (default 5)'
  }
end

#lock_mongoObject



145
146
147
148
# File 'lib/plugins/mongo_plugin.rb', line 145

def lock_mongo
  logger.info "Locking mongo"
  client.command(fsync: 1, lock: true)
end

#nameObject



75
76
77
# File 'lib/plugins/mongo_plugin.rb', line 75

def name
  "Mongo"
end

#primary?Boolean

Returns:

  • (Boolean)


110
111
112
113
114
115
116
117
# File 'lib/plugins/mongo_plugin.rb', line 110

def primary?
  carefully 'check whether this node is a primary' do
    if @primary.nil?
      @primary = client.command(isMaster: 1).first['ismaster']
    end
    @primary
  end
end

#safe_to_operate?Boolean

Returns:

  • (Boolean)


93
94
95
96
97
98
99
# File 'lib/plugins/mongo_plugin.rb', line 93

def safe_to_operate?
  # we check for strict equality with booleans here, because nil means an
  # error occurred while checking, and it is unsafe to operate
  return true if (primary? == false) or (standalone? == true)
  logger.error "This appears to be a primary member, refusing to operate"
  false
end

#standalone?Boolean

Returns:

  • (Boolean)


119
120
121
122
123
124
125
# File 'lib/plugins/mongo_plugin.rb', line 119

def standalone?
  # this will raise an error on a non-RS mongod
  client.command(replSetGetStatus: 1)
  false
rescue
  true
end

#start_mongoObject



140
141
142
143
# File 'lib/plugins/mongo_plugin.rb', line 140

def start_mongo
  logger.info "Starting mongodb via '#{options[:command]}'"
  system options[:command]
end

#stop_mongoObject



127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/plugins/mongo_plugin.rb', line 127

def stop_mongo
  logger.info 'Stopping mongodb'
  begin
    # this will always raise an exception after it completes
    client.command shutdown: 1
  rescue Mongo::Error::SocketError => e
    logger.debug "Received expected socket error after shutting down"
  end

  # we need a new connection now since the server has shut down
  @client = nil
end

#unlock_mongoObject



150
151
152
153
# File 'lib/plugins/mongo_plugin.rb', line 150

def unlock_mongo
  logger.info "Unlocking mongo"
  client.database['$cmd.sys.unlock'].find().read
end

#unlock_or_start_mongoObject



79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/plugins/mongo_plugin.rb', line 79

def unlock_or_start_mongo
  (options.retry.to_i + 1).times do
    if wired_tiger?
      return if carefully('start mongo') { start_mongo } if options.shutdown
    else
      return if carefully('unlock mongo') { unlock_mongo }
    end

    # otherwise we failed
    logger.warn "Failed to start MongoDB, retrying in #{options.interval} seconds"
    sleep options.interval.to_i
  end
end

#wired_tiger?Boolean

Returns:

  • (Boolean)


101
102
103
104
105
106
107
108
# File 'lib/plugins/mongo_plugin.rb', line 101

def wired_tiger?
  if @wired_tiger.nil?
    @wired_tiger = carefully 'detect mongodb\'s storage engine' do
      client.command(serverStatus: 1).first.has_key? WIRED_TIGER_KEY
    end
  end
  @wired_tiger
end