Skip to content

Commit

Permalink
[cassandra_check] Add cassandra_check
Browse files Browse the repository at this point in the history
  • Loading branch information
zippolyte committed Jun 29, 2017
1 parent 4fe6f3d commit ac0045b
Show file tree
Hide file tree
Showing 11 changed files with 272 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ env:
- TRAVIS_FLAVOR=apache FLAVOR_VERSION=2.4.12
- TRAVIS_FLAVOR=cassandra FLAVOR_VERSION=2.0.17
- TRAVIS_FLAVOR=cassandra FLAVOR_VERSION=2.1.14
- TRAVIS_FLAVOR=cassandra_check FLAVOR_VERSION=2.0.17
- TRAVIS_FLAVOR=cassandra_check FLAVOR_VERSION=2.1.14
- TRAVIS_FLAVOR=cassandra_check FLAVOR_VERSION=3.10
- TRAVIS_FLAVOR=couch FLAVOR_VERSION=1.6.1
- TRAVIS_FLAVOR=consul FLAVOR_VERSION=v0.6.4
- TRAVIS_FLAVOR=consul FLAVOR_VERSION=0.7.2
Expand Down
8 changes: 8 additions & 0 deletions cassandra_check/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# CHANGELOG - Cassandra_check

0.1.0/ Unreleased
==================

### Changes

* [FEATURE] adds cassandra_check integration.
29 changes: 29 additions & 0 deletions cassandra_check/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Cassandra Check

## Overview

Get metrics from cassandra databases that are not available through the [jmx integration](https://github.com/DataDog/integrations-core/tree/master/cassandra)

## Installation

Install the `dd-check-cassandra_check` package manually or with your favorite configuration manager

## Configuration

Edit the `cassandra_check.yaml` file to point to your server and port and set the keyspaces to monitor

## Validation

When you run `datadog-agent info` you should see something like the following:

Checks
======

cassandra_check
-----------
- instance #0 [OK]
- Collected 39 metrics, 0 events & 7 service checks

## Compatibility

The cassandra_check check is compatible with all major platforms
58 changes: 58 additions & 0 deletions cassandra_check/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# (C) Datadog, Inc. 2010-2016
# All rights reserved
# Licensed under Simplified BSD License (see LICENSE)

# 3rd party
from cassandra.cluster import Cluster, NoHostAvailable
from cassandra.auth import PlainTextAuthProvider

# project
from checks import AgentCheck

EVENT_TYPE = SOURCE_TYPE_NAME = 'cassandra_check'
DEFAULT_NODE_IP = 'localhost'
DEFAULT_NODE_PORT = 9042


class CassandraCheck(AgentCheck):

def __init__(self, name, init_config, agentConfig, instances=None):
AgentCheck.__init__(self, name, init_config, agentConfig, instances)

def check(self, instance):
# Get the node IP address to connect Cassandra
node_ip = instance.get("node_ip", DEFAULT_NODE_IP)
node_port = instance.get("node_port", DEFAULT_NODE_PORT)
keyspaces = instance.get("keyspaces", [])
tags = instance.get("tags", [])
connect_timeout = instance.get("connect_timeout", 5)

username = instance.get("username", "")
password = instance.get("password", "")
auth_provider = PlainTextAuthProvider(username, password)

# Try to connect to the node
cluster = Cluster([node_ip], port=node_port, auth_provider=auth_provider, connect_timeout=connect_timeout)
try:
cluster.connect(wait_for_all_pools=True)
if keyspaces:
for keyspace in keyspaces:
token_map = cluster.metadata.token_map
down_replicas = 0
for token in token_map.ring:
replicas = token_map.get_replicas(keyspace, token)
down_replicas = max(down_replicas, len([r for r in replicas if not r.is_up]))

self.gauge("cassandra.replication_failures", down_replicas,
tags=["keyspace:%s" % keyspace, "cluster:%s" % cluster.metadata.cluster_name] + tags)


except NoHostAvailable as e:
self.log.error('Could not connect to node %s:%s : %s' % (node_ip, node_port, e))
node_status = AgentCheck.CRITICAL
else:
node_status = AgentCheck.OK
finally:
cluster.shutdown()

self.service_check('cassandra.can_connect', node_status, tags=tags)
99 changes: 99 additions & 0 deletions cassandra_check/ci/cassandra_check.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
require 'ci/common'

def cassandra_check_version
ENV['FLAVOR_VERSION'] || '2.1.14' # '2.0.17'
end

def cassandra_check_rootdir
"#{ENV['INTEGRATIONS_DIR']}/cassandra_check_#{cassandra_check_version}"
end

container_name = 'dd-test-cassandra'
container_name2 = 'dd-test-cassandra2'

namespace :ci do
namespace :cassandra_check do |flavor|
task before_install: ['ci:common:before_install'] do
sh %(docker kill #{container_name} 2>/dev/null || true)
sh %(docker rm #{container_name} 2>/dev/null || true)
sh %(docker kill #{container_name2} 2>/dev/null || true)
sh %(docker rm #{container_name2} 2>/dev/null || true)
end

task :install do
Rake::Task['ci:common:install'].invoke('cassandra_check')
sh %(docker create --expose 9042 --expose 7000 --expose 7001 --expose 9160 \
-p 9042:9042 -p 7000:7000 -p 7001:7001 -p 9160:9160 --name #{container_name} cassandra:#{cassandra_check_version})
sh %(docker start #{container_name})
sh %(docker create --name #{container_name2} \
-e CASSANDRA_SEEDS="$(docker inspect --format='{{ .NetworkSettings.IPAddress }}' #{container_name})" cassandra:#{cassandra_check_version})
sh %(docker start #{container_name2})
end

task before_script: ['ci:common:before_script'] do
# Wait.for container_port
count = 0
logs = `docker logs #{container_name} 2>&1`
logs2 = `docker logs #{container_name2} 2>&1`
puts 'Waiting for Cassandra to come up'
until count == 20 || ((logs.include?('Listening for thrift clients') || logs.include?('Starting listening for CQL clients')) && \
(logs2.include?('Listening for thrift clients') || logs2.include?('Starting listening for CQL clients')))
sleep_for 4
logs = `docker logs #{container_name} 2>&1`
logs2 = `docker logs #{container_name2} 2>&1`
count += 1
end
if (logs.include?('Listening for thrift clients') || logs.include?('Starting listening for CQL clients')) && \
(logs2.include?('Listening for thrift clients') || logs2.include?('Starting listening for CQL clients'))
puts 'Cassandra is up!'
else
puts 'Logs of container 1'
sh %(docker logs #{container_name} 2>&1)
puts 'Logs of container 2'
sh %(docker logs #{container_name2} 2>&1)
raise
end
end

task script: ['ci:common:script'] do
this_provides = [
'cassandra_check'
]
Rake::Task['ci:common:run_tests'].invoke(this_provides)
end

task before_cache: ['ci:common:before_cache']

task cleanup: ['ci:common:cleanup'] do
sh %(docker kill #{container_name} 2>/dev/null || true)
sh %(docker rm #{container_name} 2>/dev/null || true)
sh %(docker kill #{container_name2} 2>/dev/null || true)
sh %(docker rm #{container_name2} 2>/dev/null || true)
end

task :execute do
exception = nil
begin
%w(before_install install before_script).each do |u|
Rake::Task["#{flavor.scope.path}:#{u}"].invoke
end
if !ENV['SKIP_TEST']
Rake::Task["#{flavor.scope.path}:script"].invoke
else
puts 'Skipping tests'.yellow
end
Rake::Task["#{flavor.scope.path}:before_cache"].invoke
rescue => e
exception = e
puts "Failed task: #{e.class} #{e.message}".red
end
if ENV['SKIP_CLEANUP']
puts 'Skipping cleanup, disposable environments are great'.yellow
else
puts 'Cleaning up'
Rake::Task["#{flavor.scope.path}:cleanup"].invoke
end
raise exception if exception
end
end
end
15 changes: 15 additions & 0 deletions cassandra_check/conf.yaml.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
init_config:

instances:
# Configuration options:
# keyspaces: a list of keyspaces to monitor
# node_ip: the IP of the cassandra node to connect to. The rest of the nodes in the cluster will be auto discovered by the cassandra driver
# For more information, see https://datastax.github.io/python-driver/api/index.html
# Default to localhost.
# node_port: the port cassandra is listening for connections.
# Default to 9042
# username/password: a set of credentials to connect to the cassandra cluster.
# tags: optional, a list of tags to be sent with the metrics
# connect_timeout: timeout, in seconds, for creating new connections. Default to 5.

- keyspaces: ["foo"]
12 changes: 12 additions & 0 deletions cassandra_check/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"maintainer": "help@datadoghq.com",
"manifest_version": "0.1.0",
"max_agent_version": "6.0.0",
"min_agent_version": "5.6.3",
"name": "cassandra_check",
"short_description": "cassandra_check description.",
"guid": "00e4a8bd-8ec2-4bb4-b725-6aaa91618d13",
"support": "contrib",
"supported_os": ["linux","mac_os","windows"],
"version": "0.1.0"
}
2 changes: 2 additions & 0 deletions cassandra_check/metadata.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
metric_name,metric_type,interval,unit_name,per_unit_name,description,orientation,integration,short_name
cassandra.replication_failures,gauge,,,,Number of replica nodes down per keyspace,-1,cassandra_check,replication failures
2 changes: 2 additions & 0 deletions cassandra_check/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# integration pip requirements
cassandra-driver==3.10.0
43 changes: 43 additions & 0 deletions cassandra_check/test_cassandra_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# (C) Datadog, Inc. 2010-2016
# All rights reserved
# Licensed under Simplified BSD License (see LICENSE)

# stdlib
from nose.plugins.attrib import attr

# 3p
from cassandra.cluster import Cluster

# project
from tests.checks.common import AgentCheckTest


@attr(requires='cassandra_check')
class TestCassandraCheck(AgentCheckTest):
"""Basic Test for cassandra_check integration."""
CHECK_NAME = 'cassandra_check'

def test_check(self):

# Create a keyspace with replication factor 2
cluster = Cluster(connect_timeout=1)
session = cluster.connect()
session.execute("CREATE KEYSPACE IF NOT EXISTS test WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor': 2}")
cluster.shutdown()

config = {
'instances': [
{'host': '127.0.0.1',
'port': 9042,
'keyspaces': ['test'],
'tags': ['foo','bar'],
'connect_timeout': 1}
]
}

self.run_check(config)
# We should have the value 1 since the driver won't be able to connect to one of the container (port not exposed)
self.assertMetric('cassandra.replication_failures', value=1, tags=['keyspace:test', 'cluster:Test Cluster', 'foo', 'bar'])
self.assertServiceCheckOK('cassandra.can_connect', tags=['foo', 'bar'])
# Raises when COVERAGE=true and coverage < 100%
self.coverage_report()
1 change: 1 addition & 0 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ test:
- rake ci:run[kafka]
- rake ci:run[docker_daemon]
- rake ci:run[kubernetes]
- rake ci:run[cassandra_check]
- bundle exec rake requirements
post:
- if [[ $(docker ps -a -q) ]]; then docker stop $(docker ps -a -q); fi

0 comments on commit ac0045b

Please sign in to comment.