Skip to content
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

changes for Python 3 compatibility #91

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions resources/collectd-cloudwatch.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ LoadPlugin python

<Plugin python>
ModulePath "/opt/collectd-plugins/"
ModulePath "/usr/lib/python3.6/"
ModulePath "/usr/local/lib/python3.6/dist-packages/"
LogTraces true
Interactive false
Import "cloudwatch_writer"
Expand Down
2 changes: 1 addition & 1 deletion src/cloudwatch/modules/awsutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ def get_aws_timestamp():


def get_datestamp():
return datetime.utcnow().strftime('%Y%m%d')
return datetime.utcnow().strftime('%Y%m%d')
9 changes: 5 additions & 4 deletions src/cloudwatch/modules/client/baserequestbuilder.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from ..awsutils import get_aws_timestamp, get_datestamp
from signer import Signer
from querystringbuilder import QuerystringBuilder
from cloudwatch.modules.awsutils import get_aws_timestamp, get_datestamp
from cloudwatch.modules.client.signer import Signer
from cloudwatch.modules.client.querystringbuilder import QuerystringBuilder


class BaseRequestBuilder(object):
"""
Expand Down Expand Up @@ -61,4 +62,4 @@ def _get_request_map(self):
}
if self.credentials.token:
canonical_map["X-Amz-Security-Token"] = self.credentials.token
return canonical_map
return canonical_map
9 changes: 4 additions & 5 deletions src/cloudwatch/modules/client/ec2getclient.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import re

from ..plugininfo import PLUGIN_NAME, PLUGIN_VERSION
from ec2requestbuilder import EC2RequestBuilder
from ..logger.logger import get_logger
from cloudwatch.modules.plugininfo import PLUGIN_NAME, PLUGIN_VERSION
from cloudwatch.modules.client.ec2requestbuilder import EC2RequestBuilder
from cloudwatch.modules.logger.logger import get_logger
from requests.adapters import HTTPAdapter
from requests.sessions import Session
import xml.etree.ElementTree as ET



class EC2GetClient(object):
"""
This is a simple HTTPClient wrapper which supports DescribeTags operation on EC2 endpoints.
Expand All @@ -30,7 +29,7 @@ def __init__(self, config_helper, connection_timeout=_DEFAULT_CONNECTION_TIMEOUT
self.timeout = (connection_timeout, response_timeout)

def _validate_and_set_endpoint(self, endpoint):
pattern = re.compile("http[s]?://*/")
pattern = re.compile(r"http[s]?://*/")
if pattern.match(endpoint) or "localhost" in endpoint:
self.endpoint = endpoint
else:
Expand Down
2 changes: 1 addition & 1 deletion src/cloudwatch/modules/client/ec2requestbuilder.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from baserequestbuilder import BaseRequestBuilder
from cloudwatch.modules.client.baserequestbuilder import BaseRequestBuilder


class EC2RequestBuilder(BaseRequestBuilder):
Expand Down
8 changes: 4 additions & 4 deletions src/cloudwatch/modules/client/putclient.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import re
import os

from ..plugininfo import PLUGIN_NAME, PLUGIN_VERSION
from requestbuilder import RequestBuilder
from ..logger.logger import get_logger
from cloudwatch.modules.plugininfo import PLUGIN_NAME, PLUGIN_VERSION
from cloudwatch.modules.client.requestbuilder import RequestBuilder
from cloudwatch.modules.logger.logger import get_logger
from requests.adapters import HTTPAdapter
from requests.sessions import Session
from tempfile import gettempdir
Expand Down Expand Up @@ -54,7 +54,7 @@ def _prepare_session(self):
self.session.mount("https://", HTTPAdapter(max_retries=self._TOTAL_RETRIES))

def _validate_and_set_endpoint(self, endpoint):
pattern = re.compile("http[s]?://*/")
pattern = re.compile(r"http[s]?://*/")
if pattern.match(endpoint) or "localhost" in endpoint:
self.endpoint = endpoint
else:
Expand Down
5 changes: 2 additions & 3 deletions src/cloudwatch/modules/client/querystringbuilder.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import operator

from ..logger.logger import get_logger
from urllib import urlencode
from cloudwatch.modules.logger.logger import get_logger
from urllib.parse import urlencode


class QuerystringBuilder(object):
Expand Down Expand Up @@ -44,7 +44,6 @@ def build_querystring_from_map(self, call_map, base_map):
url_string = urlencode(sorted_query_data).replace('+', '%20')
return url_string


def _build_metric_map(self, metric_list):
"""
Translate the list of metric objects into a single map with keys represented in the format required
Expand Down
18 changes: 10 additions & 8 deletions src/cloudwatch/modules/client/requestbuilder.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from baserequestbuilder import BaseRequestBuilder
from cloudwatch.modules.client.baserequestbuilder import BaseRequestBuilder


class RequestBuilder(BaseRequestBuilder):
"""
Expand All @@ -12,7 +13,7 @@ class RequestBuilder(BaseRequestBuilder):
_SERVICE = "monitoring"
_ACTION = "PutMetricData"
_API_VERSION = "2010-08-01"

def __init__(self, credentials, region, enable_high_resolution_metrics):
super(self.__class__, self).__init__(credentials, region, self._SERVICE, self._ACTION, self._API_VERSION, enable_high_resolution_metrics)
self.namespace = ""
Expand All @@ -23,28 +24,29 @@ def create_signed_request(self, namespace, metric_list):
self._init_timestamps()
canonical_querystring = self._create_canonical_querystring(metric_list)
signature = self.signer.create_request_signature(canonical_querystring, self._get_credential_scope(),
self.aws_timestamp, self.datestamp, self._get_canonical_headers(),
self._get_signed_headers(), self.payload)
self.aws_timestamp, self.datestamp,
self._get_canonical_headers(),
self._get_signed_headers(), self.payload)
canonical_querystring += '&X-Amz-Signature=' + signature
return canonical_querystring

def _create_canonical_querystring(self, metric_list):
"""
Creates a canonical querystring as defined in the official AWS API documentation:
http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
"""
return self.querystring_builder.build_querystring(metric_list, self._get_namespace_request_map())

def _get_namespace_request_map(self):
"""
Creates a map of request parameters and values which can be used
to build a canonical querystring
"""
canonical_map = self._get_request_map()
if (self.namespace):
if self.namespace:
canonical_map["Namespace"] = self.namespace
return canonical_map

def _get_host(self):
""" Returns the endpoint's hostname derived from the region """
if self.region == "localhost":
Expand Down
15 changes: 13 additions & 2 deletions src/cloudwatch/modules/client/signer.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,24 @@ def _build_string_to_sign(self, aws_timestamp, credential_scope, canonical_reque
return self.algorithm + "\n" + aws_timestamp + '\n' + credential_scope + '\n' + self._hash(canonical_request)

def _hash(self, data):
# change type to `bytes`
if type(data) is str:
data = data.encode("utf-8")
return sha256(data).hexdigest()

def _sign(self, key, msg):
return hmac.new(key, msg.encode("utf-8"), sha256).digest()
# change type to `bytes`
if type(key) is str:
key = key.encode("utf-8")
if type(msg) is str:
msg = msg.encode("utf-8")
return hmac.new(key, msg, sha256).digest()

def _build_signature_key(self, key, date_stamp, region_name, service_name):
kDate = self._sign(('AWS4' + key).encode('utf-8'), date_stamp)
# change type to `str`
if type(key) is bytes:
key = key.decode("utf-8")
kDate = self._sign('AWS4' + key, date_stamp)
kRegion = self._sign(kDate, region_name)
kService = self._sign(kRegion, service_name)
kSigning = self._sign(kService, self._V4_TERMINATOR)
Expand Down
9 changes: 8 additions & 1 deletion src/cloudwatch/modules/collectd.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,30 @@
The collectd stub is used to allow testing every part of this module without the need of installing and running collectd.
"""


def register_config(*args):
pass


def register_init(*args):
pass


def register_write(*args, **kwargs):
pass


def debug(msg):
pass


def info(msg):
pass


def warning(msg):
pass


def error(msg):
pass
pass
18 changes: 9 additions & 9 deletions src/cloudwatch/modules/configuration/confighelper.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import os
from ..logger.logger import get_logger
from configreader import ConfigReader
from metadatareader import MetadataReader
from credentialsreader import CredentialsReader
from whitelist import Whitelist, WhitelistConfigReader
from ..client.ec2getclient import EC2GetClient
from cloudwatch.modules.logger.logger import get_logger
from cloudwatch.modules.configuration.configreader import ConfigReader
from cloudwatch.modules.configuration.metadatareader import MetadataReader
from cloudwatch.modules.configuration.credentialsreader import CredentialsReader
from cloudwatch.modules.configuration.whitelist import Whitelist, WhitelistConfigReader
from cloudwatch.modules.client.ec2getclient import EC2GetClient
import traceback


class ConfigHelper(object):
"""
The configuration helper is responsible for obtaining configuration data from number
Expand Down Expand Up @@ -135,12 +136,11 @@ def _load_hostname(self):
try:
self.host = self.metadata_reader.get_instance_id()
except Exception as e:
ConfigHelper._LOGGER.warning("Cannot retrieve Instance ID from the local metadata server. Cause: " + str(e) +
" Using host information provided by Collectd.")
ConfigHelper._LOGGER.warning("Cannot retrieve Instance ID from the local metadata server. Cause: " + str(e) + " Using host information provided by Collectd.")

def _set_ec2_endpoint(self):
""" Creates endpoint from region information """
if self.region is "localhost":
if self.region == "localhost":
self.ec2_endpoint = "http://" + self.region + "/"
elif self.region.startswith("cn-"):
self.ec2_endpoint = "https://ec2." + self.region + ".amazonaws.com.cn/"
Expand Down
6 changes: 3 additions & 3 deletions src/cloudwatch/modules/configuration/configreader.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from ..logger.logger import get_logger
from readerutils import ReaderUtils
from cloudwatch.modules.logger.logger import get_logger
from cloudwatch.modules.configuration.readerutils import ReaderUtils


class ConfigReader(object):
Expand Down Expand Up @@ -50,7 +50,7 @@ def __init__(self, config_path):
self.push_asg = self._PUSH_ASG_DEFAULT_VALUE
self.push_constant = self._PUSH_CONSTANT_DEFAULT_VALUE
self.constant_dimension_value = ''
self.proxy_server_name=''
self.proxy_server_name = ''
self.proxy_server_port = ''
self.enable_high_resolution_metrics = self._ENABLE_HIGH_DEFINITION_METRICS_DEFAULT_VALUE
self.flush_interval_in_seconds = ''
Expand Down
9 changes: 4 additions & 5 deletions src/cloudwatch/modules/configuration/credentialsreader.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from ..awscredentials import AWSCredentials
from readerutils import ReaderUtils
from ..logger.logger import get_logger
from cloudwatch.modules.awscredentials import AWSCredentials
from cloudwatch.modules.configuration.readerutils import ReaderUtils
from cloudwatch.modules.logger.logger import get_logger


class CredentialsReader(object):
Expand All @@ -23,7 +23,7 @@ class CredentialsReader(object):
_ACCESS_CONFIG_KEY = "aws_access_key"
_SECRET_CONFIG_KEY = "aws_secret_key"

#This is the format the SDK uses.
# This is the format the SDK uses.
_ACCESS_CONFIG_KEY_AWS_FORMAT = "aws_access_key_id"
_SECRET_CONFIG_KEY_AWS_FORMAT = "aws_secret_access_key"

Expand Down Expand Up @@ -57,4 +57,3 @@ def _parse_credentials_file(self):

class CredentialsReaderException(Exception):
pass

6 changes: 3 additions & 3 deletions src/cloudwatch/modules/configuration/metadatareader.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from json import loads
from requests import Session, codes
from requests.adapters import HTTPAdapter
from ..logger.logger import get_logger
from ..awscredentials import AWSCredentials
from cloudwatch.modules.logger.logger import get_logger
from cloudwatch.modules.awscredentials import AWSCredentials


class MetadataReader(object):
Expand Down Expand Up @@ -63,7 +63,7 @@ def _get_metadata(self, request):
if result.status_code is codes.ok:
return str(result.text)
else:
self._LOGGER.error("The request: '" + str(request) + "' failed with status code: '" + str(result.status_code) + "' and message: '" + str(result.text) +"'.")
self._LOGGER.error("The request: '" + str(request) + "' failed with status code: '" + str(result.status_code) + "' and message: '" + str(result.text) + "'.")
raise MetadataRequestException("Cannot retrieve configuration from metadata service. Status code: " + str(result.status_code))


Expand Down
4 changes: 2 additions & 2 deletions src/cloudwatch/modules/configuration/readerutils.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import re
import os

from ..logger.logger import get_logger
from cloudwatch.modules.logger.logger import get_logger


class ReaderUtils(object):

_LOGGER = get_logger(__name__)
_COMMENT_CHARACTER = '#'
_AWS_PROFILE_PATTERN = re.compile("^\s*\[[\w]+\]\s*$")
_AWS_PROFILE_PATTERN = re.compile(r"^\s*\[[\w]+\]\s*$")

def __init__(self, path):
self.path = path
Expand Down
16 changes: 7 additions & 9 deletions src/cloudwatch/modules/configuration/whitelist.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import re
from os import path
from string import strip
from threading import Lock
import sys

from configreader import ConfigReader
from ..logger.logger import get_logger
from cloudwatch.modules.configuration.configreader import ConfigReader
from cloudwatch.modules.logger.logger import get_logger


class WhitelistConfigReader(object):
Expand All @@ -19,7 +19,7 @@ class WhitelistConfigReader(object):
END_STRING = "$"
EMPTY_REGEX = START_STRING + END_STRING

PASS_THROUGH_REGEX_STRING = "^\.[\*\+]?\s.*$|^.*?\s\.[\*\+]|^\.[\*\+]$" # matches single .*, .+ strings
PASS_THROUGH_REGEX_STRING = r"^\.[\*\+]?\s.*$|^.*?\s\.[\*\+]|^\.[\*\+]$" # matches single .*, .+ strings
# as well as strings with .* or .+ preceded or followed by whitespace.

def __init__(self, whitelist_config_path, pass_through_allowed):
Expand All @@ -43,7 +43,7 @@ def get_regex_list(self):

def _get_whitelisted_names_from_file(self, whitelist_path):
with open(whitelist_path) as whitelist_file:
return self._filter_valid_regexes(map(strip, whitelist_file))
return self._filter_valid_regexes(map(str.strip, whitelist_file))

def _create_whitelist_file(self, whitelist_path):
if not path.exists(whitelist_path):
Expand All @@ -63,7 +63,8 @@ def _is_valid_regex(self, regex_string):
return True
return False
except Exception as e:
self._LOGGER.warning("The whitelist rule: '{}' is invalid, reason: {}".format(str(regex_string), str(e.message)))
_traceback = sys.exc_info()[2]
self._LOGGER.warning("The whitelist rule: '{}' is invalid, reason: {}".format(str(regex_string), str(e.with_traceback(_traceback).msg)))
return False

def _is_allowed_regex(self, regex_string):
Expand Down Expand Up @@ -138,6 +139,3 @@ def is_whitelisted(self, metric_key):
self._allowed_metrics[metric_key] = False
self.blocked_metric_log.log_metric(metric_key)
return self._allowed_metrics[metric_key]



Loading