Skip to content

RUBY-3296 Write to log when non-genuine host is detected #2791

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions lib/mongo/cluster.rb
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ def initialize(seeds, monitoring, options = Options::Redacted.new)
recreate_topology(topology, opening_topology)
end

possibly_warn_about_compatibility!

if load_balanced?
# We are required by the specifications to produce certain SDAM events
# when in load-balanced topology.
Expand Down Expand Up @@ -1082,6 +1084,30 @@ def recreate_topology(new_topology_template, previous_topology)
Monitoring::Event::TopologyChanged.new(previous_topology, @topology)
)
end

COSMOSDB_HOST_PATTERNS = %w[ .cosmos.azure.com ]
COSMOSDB_LOG_MESSAGE = 'You appear to be connected to a CosmosDB cluster. ' \
'For more information regarding feature compatibility and support please visit ' \
'https://www.mongodb.com/supportability/cosmosdb'

DOCUMENTDB_HOST_PATTERNS = %w[ .docdb.amazonaws.com .docdb-elastic.amazonaws.com ]
DOCUMENTDB_LOG_MESSAGE = 'You appear to be connected to a DocumentDB cluster. ' \
'For more information regarding feature compatibility and support please visit ' \
'https://www.mongodb.com/supportability/documentdb'

# Compares the server hosts with address suffixes of known services
# that provide limited MongoDB API compatibility, and warns about them.
def possibly_warn_about_compatibility!
if topology.server_hosts_match_any?(COSMOSDB_HOST_PATTERNS)
log_info COSMOSDB_LOG_MESSAGE
return
end

if topology.server_hosts_match_any?(DOCUMENTDB_HOST_PATTERNS)
log_info DOCUMENTDB_LOG_MESSAGE
return
end
end
end
end

Expand Down
16 changes: 16 additions & 0 deletions lib/mongo/cluster/topology/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,22 @@ def new_max_set_version(description)
end
end

# Compares each server address against the list of patterns.
#
# @param [ Array<String> ] patterns the URL suffixes to compare
# each server against.
#
# @return [ true | false ] whether any of the addresses match any of
# the patterns or not.
#
# @api private
def server_hosts_match_any?(patterns)
server_descriptions.any? do |addr_spec, _desc|
addr, _port = addr_spec.split(/:/)
patterns.any? { |pattern| addr.end_with?(pattern) }
end
end

private

# Validates and/or transforms options as necessary for the topology.
Expand Down
36 changes: 36 additions & 0 deletions spec/mongo/cluster_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require 'spec_helper'
require 'support/recording_logger'

# let these existing styles stand, rather than going in for a deep refactoring
# of these specs.
Expand Down Expand Up @@ -84,6 +85,41 @@
)
end
end

context 'when a non-genuine host is detected' do
before { described_class.new(host_names, monitoring, logger: logger, monitoring_io: false) }

let(:logger) { RecordingLogger.new }

shared_examples 'an action that logs' do
it 'writes a warning to the log' do
expect(logger.lines).to include(a_string_matching(expected_log_output))
end
end

context 'when CosmosDB is detected' do
let(:host_names) { %w[ xyz.cosmos.azure.com ] }
let(:expected_log_output) { %r{https://www.mongodb.com/supportability/cosmosdb} }

it_behaves_like 'an action that logs'
end

context 'when DocumentDB is detected' do
let(:expected_log_output) { %r{https://www.mongodb.com/supportability/documentdb} }

context 'with docdb uri' do
let(:host_names) { [ 'xyz.docdb.amazonaws.com' ] }

it_behaves_like 'an action that logs'
end

context 'with docdb-elastic uri' do
let(:host_names) { [ 'xyz.docdb-elastic.amazonaws.com' ] }

it_behaves_like 'an action that logs'
end
end
end
end

describe '#==' do
Expand Down
27 changes: 27 additions & 0 deletions spec/support/recording_logger.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true
# rubocop:todo all

require 'stringio'

# A "Logger-alike" class, quacking like ::Logger, used for recording messages
# as they are written to the log
class RecordingLogger < Logger
def initialize(*args, **kwargs)
@buffer = StringIO.new
super(@buffer, *args, **kwargs)
end

# Accesses the raw contents of the log
#
# @return [ String ] the raw contents of the log
def contents
@buffer.string
end

# Returns the contents of the log as individual lines.
#
# @return [ Array<String> ] the individual log lines
def lines
contents.split(/\n/)
end
end