diff --git a/.gitignore b/.gitignore index bbe711c..9ae6fb0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .coverage *.pyc .DS_Store +.vscode* +.vscode/* diff --git a/README.md b/README.md index 3e8f224..e97ead4 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,10 @@ The default location of the configuration file used by collectd-cloudwatch plugi * __flush_interval_in_seconds__ - The flush_interval_in_seconds is used for flush interval, it means how long plugin should flush the metrics to Cloudwatch * __whitelist_pass_through__ - Used to enable potentially unsafe regular expressions. By default regex such as a line containing `.*` or `.+` only is automatically disabled in the whitelist configuration. Setting this value to True may result in a large number of metrics being published. Before changing this parameter, read [pricing information](https://aws.amazon.com/cloudwatch/pricing/) to understand how to estimate your bill. - * __push_asg__ - Used to include the Auto-Scaling Group as a dimension for all metrics (see `Adding additional dimensions to metrics` below for details) - * __push_constant__ - Used to include a Fixed dimension (see `constant_dimension_value` below) on all metrics. Useful for collating all metrics of a certain type (see `Adding additional dimensions to metrics` below for details) - * __constant_dimension_value__ - Used to specify the value for the Fixed dimension (see `Adding additional dimensions to metrics` below for details) + * __dimensions_path__ - Path to file that contains custom dimension definition. (see `Adding EC2 metadata dimensions to metrics` below for details) + * __push_asg__ - Used to include the Auto-Scaling Group as a dimension for all metrics (see `Adding simple dimensions to metrics` below for details) + * __push_constant__ - Used to include a Fixed dimension (see `constant_dimension_value` below) on all metrics. Useful for collating all metrics of a certain type (see `Adding simple dimensions to metrics` below for details) + * __constant_dimension_value__ - Used to specify the value for the Fixed dimension (see `Adding simple dimensions to metrics` below for details) * __debug__ - Provides verbose logging of metrics emitted to CloudWatch #### Example configuration file @@ -41,6 +42,7 @@ host = "Server1" proxy_server_name = "http://myproxyserver.com" proxy_server_port = "8080" whitelist_pass_through = False +dimensions_path = "/opt/collectd-plugins/cloudwatch/config/dimensions" push_asg = False push_constant = True constant_dimension_value = "ALL" @@ -50,7 +52,7 @@ flush_interval_in_seconds = 60 ``` -##### Adding additional dimensions to metrics +##### Adding simple dimensions to metrics We support adding both the ASG name to dimensions, as well as a "fixed dimension". Fixed dimensions are an additional value that will be added all metrics. ###### Example configuration file @@ -70,6 +72,26 @@ The above configuration will result in all metrics being pushed with "FixedDimen The above configuration will push the AutoScaling Group name for metrics as well +###### Adding EC2 metadata dimensions to metrics +User can specify in a dimension file the instance metadata that he/she wants to be pushed to aws cloudwatch along with the metric information. For example, a user can specify region, availability-zone, private-ip, instanceid, and more in the dimension file. In effect those attributes will be pushed along with the metric data to aws cloudwatch giving more clarity and information to the user about the particular metric(s). + +Usage: +Create dimensions file in whatever location you want. +Recommended Path: /opt/collectd-plugins/cloudwatch/config/dimensions + +Sample Dimensions File: +``` +Host +PrivateIp +InstanceId +Region +``` +After setup.py is ran there will be a dimensions file located at the dimensions_path file location. By default, dimensions will be Host and PluginInstance. Any key within the [instance dimension document](http://169.254.169.254/latest/dynamic/instance-identity/document) is supported however the first letter of the key will have to be captilized and there should be no spaces at the end of the key. + +For example, the key in the identity document the key `imageId` would become `ImageId` in the dimensions file. + +If you update a dimension in the dimensions file collectd will need to be restarted. Setup.py must be ran in interactive mode. + ### AWS account configuration The account configuration is optional for EC2 instances with IAM Role attached. By default the AWS account configuration file is expected to be stored in: `/opt/collectd-plugins/cloudwatch/config/.aws/credentials`. The following parameters can be configured in the above file: diff --git a/src/cloudwatch/config/plugin.conf b/src/cloudwatch/config/plugin.conf index ea2d972..18d32c7 100644 --- a/src/cloudwatch/config/plugin.conf +++ b/src/cloudwatch/config/plugin.conf @@ -16,6 +16,9 @@ whitelist_pass_through = False # The debug parameter enables verbose logging of published metrics debug = False +# The path to the Dimensions file. This path has to be provided if you want extra metadata sent along with metric data to cloudwatch +#dimensions_path = "/opt/collectd-plugins/cloudwatch/config/dimensions" + # Wheter or not to push the ASG as part of the dimension. # WARNING: ENABLING THIS WILL LEAD TO CREATING A LARGE NUMBER OF METRICS. push_asg = False diff --git a/src/cloudwatch/modules/configuration/confighelper.py b/src/cloudwatch/modules/configuration/confighelper.py index f013085..67dedd9 100644 --- a/src/cloudwatch/modules/configuration/confighelper.py +++ b/src/cloudwatch/modules/configuration/confighelper.py @@ -3,6 +3,7 @@ from configreader import ConfigReader from metadatareader import MetadataReader from credentialsreader import CredentialsReader +from dimensionsreader import DimensionsReader from whitelist import Whitelist, WhitelistConfigReader from ..client.ec2getclient import EC2GetClient import traceback @@ -27,6 +28,7 @@ class ConfigHelper(object): _DEFAULT_AGENT_ROOT_FOLDER = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, './config/') # '/opt/AmazonCloudWatchAgent/' _DEFAULT_CONFIG_PATH = _DEFAULT_AGENT_ROOT_FOLDER + 'plugin.conf' _DEFAULT_CREDENTIALS_PATH = _DEFAULT_AGENT_ROOT_FOLDER + ".aws/credentials" + _DEFAULT_DIMENSIONS_PATH = _DEFAULT_AGENT_ROOT_FOLDER + 'dimensions' _METADATA_SERVICE_ADDRESS = 'http://169.254.169.254/' WHITELIST_CONFIG_PATH = _DEFAULT_AGENT_ROOT_FOLDER + 'whitelist.conf' BLOCKED_METRIC_PATH = _DEFAULT_AGENT_ROOT_FOLDER + 'blocked_metrics' @@ -45,6 +47,7 @@ def __init__(self, config_path=_DEFAULT_CONFIG_PATH, metadata_server=_METADATA_S self.debug = False self.pass_through = False self.push_asg = False + self.dimensions = [] self.push_constant = False self.constant_dimension_value = '' self.enable_high_resolution_metrics = False @@ -74,7 +77,9 @@ def _load_configuration(self): self.config_reader = ConfigReader(self._config_path) self.credentials_reader = CredentialsReader(self._get_credentials_path()) self.metadata_reader = MetadataReader(self._metadata_server) + self.dimensions_reader = DimensionsReader(self._get_dimensions_path()) self._load_credentials() + self._load_dimensions() self._load_region() self._load_hostname() self._load_proxy_server_name() @@ -110,6 +115,23 @@ def _load_credentials(self): def _get_credentials_from_iam_role(self): """ Queries IAM Role metadata for latest credentials """ return self.metadata_reader.get_iam_role_credentials(self.metadata_reader.get_iam_role_name()) + + def _get_dimensions_path(self): + dimensions_path = self.config_reader.dimensions_path + self._LOGGER.info("Dimensions Path: " + str(dimensions_path)) + if not self.config_reader.dimensions_path: + dimensions_path = self._DEFAULT_DIMENSIONS_PATH + return dimensions_path + + def _load_dimensions(self): + """ + Tries to load dimensions based on the path to the file given in the plugin configuration file. If such file does not exist + or does not contain uncommented dimensions, then default dimensions are used. + """ + self.dimensions = self.dimensions_reader.dimensions + if not self.dimensions: + self.dimensions = None + self._LOGGER.info("Dimensions set to None") def _load_region(self): """ diff --git a/src/cloudwatch/modules/configuration/configreader.py b/src/cloudwatch/modules/configuration/configreader.py index 1da5a65..007e078 100644 --- a/src/cloudwatch/modules/configuration/configreader.py +++ b/src/cloudwatch/modules/configuration/configreader.py @@ -33,6 +33,7 @@ class ConfigReader(object): DEBUG_CONFIG_KEY = "debug" PASS_THROUGH_CONFIG_KEY = "whitelist_pass_through" PUSH_ASG_KEY = "push_asg" + DIMENSIONS_PATH_KEY = "dimensions_path" PUSH_CONSTANT_KEY = "push_constant" CONSTANT_DIMENSION_KEY = "constant_dimension_value" PROXY_SERVER_NAME_KEY = "proxy_server_name" @@ -48,6 +49,7 @@ def __init__(self, config_path): self.pass_through = self._PASS_THROUGH_DEFAULT_VALUE self.debug = self._DEBUG_DEFAULT_VALUE self.push_asg = self._PUSH_ASG_DEFAULT_VALUE + self.dimensions_path = "" self.push_constant = self._PUSH_CONSTANT_DEFAULT_VALUE self.constant_dimension_value = '' self.proxy_server_name='' @@ -76,5 +78,6 @@ def _parse_config_file(self): self.pass_through = self.reader_utils.try_get_boolean(self.PASS_THROUGH_CONFIG_KEY, self._PASS_THROUGH_DEFAULT_VALUE) self.debug = self.reader_utils.try_get_boolean(self.DEBUG_CONFIG_KEY, self._DEBUG_DEFAULT_VALUE) self.push_asg = self.reader_utils.try_get_boolean(self.PUSH_ASG_KEY, self._PUSH_ASG_DEFAULT_VALUE) + self.dimensions_path = self.reader_utils.get_string(self.DIMENSIONS_PATH_KEY) self.push_constant = self.reader_utils.try_get_boolean(self.PUSH_CONSTANT_KEY, self._PUSH_CONSTANT_DEFAULT_VALUE) self.constant_dimension_value = self.reader_utils.get_string(self.CONSTANT_DIMENSION_KEY) diff --git a/src/cloudwatch/modules/configuration/dimensionsreader.py b/src/cloudwatch/modules/configuration/dimensionsreader.py new file mode 100644 index 0000000..81cc6db --- /dev/null +++ b/src/cloudwatch/modules/configuration/dimensionsreader.py @@ -0,0 +1,41 @@ +from readerutils import ReaderUtils +from ..logger.logger import get_logger + + +class DimensionsReader(object): + """ + The dimensions file reader class that is responsible for reading and parsing file containing AWS dimensions. + + The credentials file is a simple text file in format: + dimension1 + dimension2 + + Keyword arguments: + dimensions_path -- the path for the credentials file to be parsed (Required) + """ + + _LOGGER = get_logger(__name__) + + def __init__(self, dimensions_path): + self.dimensions_path = dimensions_path + self.dimensions = None + try: + self.reader_utils = ReaderUtils(dimensions_path) + self._parse_dimensions_file() + except Exception as e: + self._LOGGER.warning("Cannot read AWS dimensions from file. Defaulting to default dimensions.") + + def _parse_dimensions_file(self): + """ + This method retrieves values form preprocessed configuration list + in format: + value + value2 + """ + dimensions_list = self.reader_utils.get_dimensions() + if not dimensions_list: + self._LOGGER.warning("Cannot read AWS dimensions from file. Defaulting to default dimensions.") + self.dimensions = dimensions_list + +class DimensionsReaderException(Exception): + pass \ No newline at end of file diff --git a/src/cloudwatch/modules/configuration/readerutils.py b/src/cloudwatch/modules/configuration/readerutils.py index ff7207f..6550c70 100644 --- a/src/cloudwatch/modules/configuration/readerutils.py +++ b/src/cloudwatch/modules/configuration/readerutils.py @@ -9,6 +9,7 @@ class ReaderUtils(object): _LOGGER = get_logger(__name__) _COMMENT_CHARACTER = '#' _AWS_PROFILE_PATTERN = re.compile("^\s*\[[\w]+\]\s*$") + _NONDIMENSIONS_PATTERN = re.compile("^\s") def __init__(self, path): self.path = path @@ -17,6 +18,9 @@ def __init__(self, path): def get_string(self, key): return self._find_value_by_key(key) + + def get_dimensions(self): + return self._find_dimensions() def get_boolean(self, key): value = self._find_value_by_key(key) @@ -35,7 +39,7 @@ def try_get_boolean(self, key, default_value): def _find_value_by_key(self, key): config_list = self._load_config_as_list(self.path) for entry in config_list: - if not entry or entry[0] == self._COMMENT_CHARACTER or self._AWS_PROFILE_PATTERN.match(entry): + if not entry or entry[0] == (self._COMMENT_CHARACTER or self._AWS_PROFILE_PATTERN.match(entry)): continue # skip empty and commented lines try: entry_key, entry_value = entry.split('=', 1) @@ -46,6 +50,19 @@ def _find_value_by_key(self, key): self._LOGGER.error("Cannot read configuration entry: " + str(entry)) raise ValueError("Invalid syntax for entry '" + entry + "'.") return "" + + def _find_dimensions(self): + config_list = self._load_config_as_list(self.path) + dimensions_list = [] + for entry in config_list: + if not entry or entry[0] == self._COMMENT_CHARACTER or self._NONDIMENSIONS_PATTERN.match(entry): + continue # skip empty and commented lines + try: + dimensions_list.append(entry) + except: + self._LOGGER.error("Cannot read configuration entry: " + str(entry)) + raise ValueError("Invalid syntax for dimension entry '" + entry + "'.") + return dimensions_list def _strip_quotes(self, string): return re.sub(r"^'|'$|^\"|\"$", '', string) diff --git a/src/cloudwatch/modules/metricdata.py b/src/cloudwatch/modules/metricdata.py index 1669e66..8960971 100644 --- a/src/cloudwatch/modules/metricdata.py +++ b/src/cloudwatch/modules/metricdata.py @@ -1,6 +1,9 @@ import awsutils as awsutils import plugininfo import datetime +import json +import urllib2 +from logger.logger import get_logger class MetricDataStatistic(object): """ @@ -78,6 +81,7 @@ class MetricDataBuilder(object): vl -- The Collectd ValueList object with metric information adjusted_time - The adjusted_time is the time adjusted according to storage resolution """ + _LOGGER = get_logger(__name__) def __init__(self, config_helper, vl, adjusted_time=None): self.config = config_helper @@ -123,14 +127,29 @@ def _build_constant_dimension(self): return dimensions def _build_metric_dimensions(self): - dimensions = { - "Host" : self._get_host_dimension(), - "PluginInstance" : self._get_plugin_instance_dimension() - } - if self.config.push_asg: - dimensions["AutoScalingGroup"] = self._get_autoscaling_group() - if self.config.push_constant: - dimensions["FixedDimension"] = self.config.constant_dimension_value + dimensions = {} + metadata = self._get_metadata() + if self.config.dimensions: + for dim in self.config.dimensions: + if dim.lower() == 'host': + dimensions["Host"] = self._get_host_dimension() + elif dim.lower() == 'plugininstance': + dimensions[dim] = self._get_plugin_instance_dimension() + else: + dimensions[dim] = str(metadata.get(dim[:1].lower() + dim[1:])) + if self.config.push_asg: + dimensions["AutoScalingGroup"] = self._get_autoscaling_group() + if self.config.push_constant: + dimensions["FixedDimension"] = self.config.constant_dimension_value + else: + dimensions = { + "Host" : self._get_host_dimension(), + "PluginInstance" : self._get_plugin_instance_dimension(), + } + if self.config.push_asg: + dimensions["AutoScalingGroup"] = self._get_autoscaling_group() + if self.config.push_constant: + dimensions["FixedDimension"] = self.config.constant_dimension_value return dimensions def _get_plugin_instance_dimension(self): @@ -147,3 +166,25 @@ def _get_autoscaling_group(self): if self.config.asg_name: return self.config.asg_name return "NONE" + + def _get_metadata(self): + ## regarding commandlist below: + ## http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html + ## Due to the dynamic nature of instance identity documents and signatures, + ## we recommend retrieving the instance identity document and signature regularly. + dimensionsList = [] + url = "http://169.254.169.254/latest/dynamic/instance-identity/document" + + req = urllib2.Request(url) + try: + response = urllib2.urlopen(req) + except urllib2.URLError as e: + if hasattr(e, 'reason'): + self._LOGGER.error("We failed to reach a server. Reason: " + e.reason) + elif hasattr(e, 'code'): + self._LOGGER.error("The server couldn't fulfill the request. Error code: " + e.code) + for line in response: + dimensionsList.append(line.rstrip()) + output = "".join(dimensionsList) + instanceDimensions = json.loads(output) + return instanceDimensions \ No newline at end of file diff --git a/src/setup.py b/src/setup.py index 6719d98..d058b40 100755 --- a/src/setup.py +++ b/src/setup.py @@ -36,6 +36,7 @@ TAR_FILE = GITHUB_USER_NAME + "-collectd-cloudwatch.tar.gz" DOWNLOAD_PLUGIN_DIR = GITHUB_USER_NAME + "-collectd-cloudwatch*" DEFAULT_PLUGIN_CONFIGURATION_DIR = "/opt/collectd-plugins/cloudwatch/config" +DEFAULT_DIMENSIONS_FILE = path.join(DEFAULT_PLUGIN_CONFIGURATION_DIR, "dimensions") NEW_PLUGIN_FILES = DOWNLOAD_PLUGIN_DIR + "/src/*" RECOMMENDED_COLLECTD_CONFIGURATION = DOWNLOAD_PLUGIN_DIR + "/resources/collectd.conf" RECOMMENDED_WHITELIST = DOWNLOAD_PLUGIN_DIR + "/resources/whitelist.conf" @@ -287,6 +288,7 @@ class PluginConfig(object): PROXY_SERVER_PORT = "proxy_server_port" PASS_THROUGH_KEY = "whitelist_pass_through" PUSH_ASG_KEY = "push_asg" + DIMENSIONS_PATH_KEY = "dimensions_path" PUSH_CONSTANT_KEY = "push_constant" CONSTANT_DIMENSION_VALUE_KEY = "constant_dimension_value" DEBUG_KEY = "debug" @@ -295,7 +297,7 @@ class PluginConfig(object): ENABLE_HIGH_DEFINITION_METRICS = "enable_high_resolution_metrics" FLUSH_INTERVAL_IN_SECONDS = "flush_interval_in_seconds" - def __init__(self, credentials_path=None, access_key=None, secret_key=None, region=None, host=None, proxy_server_name=None, proxy_server_port=None, push_asg=None, push_constant=None, constant_dimension_value=None, enable_high_resolution_metrics=False, flush_interval_in_seconds=None): + def __init__(self, credentials_path=None, access_key=None, secret_key=None, region=None, host=None, proxy_server_name=None, proxy_server_port=None, push_asg=None, dimensions_path=None, push_constant=None, constant_dimension_value=None, enable_high_resolution_metrics=False, flush_interval_in_seconds=None): self.credentials_path = credentials_path self.access_key = access_key self.secret_key = secret_key @@ -306,11 +308,13 @@ def __init__(self, credentials_path=None, access_key=None, secret_key=None, regi self.debug = False self.pass_through = False self.credentials_file_exist = False + self.dimensions_file_exist = False self.proxy_server_name = proxy_server_name self.proxy_server_port = proxy_server_port self.enable_high_resolution_metrics = enable_high_resolution_metrics self.flush_interval_in_seconds = flush_interval_in_seconds self.push_asg = push_asg + self.dimensions_path = dimensions_path self.push_constant = push_constant self.constant_dimension_value = constant_dimension_value @@ -322,7 +326,7 @@ def __init__(self, plugin_config, metadata_reader, collectd_info, non_interactive, region, host, proxy_name, proxy_port, enable_high_resolution_metrics, flush_interval_in_seconds, access_key, secret_key, creds_path, - installation_method, push_asg, push_constant, dimension_value, + installation_method, push_asg, dimensions_path, push_constant, dimension_value, debug_setup, debug): self.config = plugin_config self.metadata_reader = metadata_reader @@ -339,6 +343,7 @@ def __init__(self, plugin_config, metadata_reader, collectd_info, self.creds_path = creds_path self.installation_method = installation_method self.push_asg = push_asg + self.dimensions_path = dimensions_path self.push_constant = push_constant self.dimension_value = dimension_value self.debug = debug @@ -352,6 +357,7 @@ def run(self): self._configure_proxy_server_name_non_interactive() self._configure_proxy_server_port_non_interactive() self._configure_push_asg_non_interactive() + self._configure_dimensions_path_non_interactive() self._configure_push_constant_non_interactive() self._configure_enable_high_resolution_metrics_non_interactive() self._configure_flush_interval_in_seconds_non_interactive() @@ -366,11 +372,36 @@ def run(self): self._configure_proxy_server_name() self._configure_proxy_server_port() self._configure_push_asg() + self._configure_dimensions_path() self._configure_push_constant() self._configure_enable_high_resolution_metrics() self._configure_flush_interval_in_seconds() self._configure_plugin_installation_method() + def _configure_dimensions_path_non_interactive(self): + try: + with open(DEFAULT_DIMENSIONS_FILE, "w") as dimensions_file: + dimensions_file.write("""#You can use all of the instance identity documents dimensions\n#Make sure that the first letter of the dimension is captilized and there are no spaces at the end of the dimension\n#For more information on dimensions that can be used:https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html\n#Host\n#PluginInstance""") + print(Color.green("Dimensions File written successfully.")) + except IOError as e: + raise InstallationFailedException("Could not write dimensions file. Cause: {}".format(str(e))) + + def _get_dimensions_path(self): + recommended_path = DEFAULT_DIMENSIONS_FILE + dims_path = "" + while not path.isabs(dims_path): + dims_path = Prompt( + message="\nEnter absolute path to Dimensions file [" + Color.green(recommended_path) + "]: ", + default=recommended_path).run() + return dims_path + + def _configure_dimensions_path(self): + self.config.dimensions_path = self._get_dimensions_path() + self.config.dimensions_file_exist = path.exists(self.config.dimensions_path) + if not self.config.dimensions_file_exist: + print(Color.red("Dimensions file path doesn't exist please renter the correct path: \n")) + self._configure_dimensions_path() + def _configure_push_asg_non_interactive(self): if self.push_asg: self.config.push_asg = True @@ -603,6 +634,7 @@ def _debug_setup(self): logger.info('FLUSH INTERVAL IN SECONDS: {}'.format( self.config.flush_interval_in_seconds)) logger.info('CREDENTIALS PATH: {}'.format(self.config.credentials_path)) + logger.info('DIMENSIONS FILE PATH: {}'.format(self.config.dimensions_path)) logger.info('METHOD ONLY ADD PLUGIN: {}'.format(self.config.only_add_plugin)) logger.info('USE RECOMMENDED CONFIG: {}'.format(self.config.use_recommended_collectd_config)) logger.info('REGION: {}'.format(self.config.region)) @@ -666,6 +698,9 @@ class PluginConfigWriter(object): # WARNING: ENABLING THIS WILL LEAD TO CREATING A LARGE NUMBER OF METRICS. $push_asg$ +# The path to the Dimensions file. This path has to be provided if you want extra metadata sent along with metric data to cloudwatch +$dimensions_path$ + # Whether or not to push the constant value to CWM as a metric $push_constant$ @@ -724,6 +759,7 @@ def _prepare_config(self): config = self._replace_with_value(config, self.plugin_config.ENABLE_HIGH_DEFINITION_METRICS, self.plugin_config.enable_high_resolution_metrics) config = self._replace_with_value(config, self.plugin_config.FLUSH_INTERVAL_IN_SECONDS, self.plugin_config.flush_interval_in_seconds) config = self._replace_with_value(config, self.plugin_config.PUSH_ASG_KEY, self.plugin_config.push_asg) + config = self._replace_with_value(config, self.plugin_config.DIMENSIONS_PATH_KEY, self.plugin_config.dimensions_path) config = self._replace_with_value(config, self.plugin_config.PUSH_CONSTANT_KEY, self.plugin_config.push_constant) config = self._replace_with_value(config, self.plugin_config.CONSTANT_DIMENSION_VALUE_KEY, self.plugin_config.constant_dimension_value) return config @@ -815,6 +851,11 @@ def main(): help='Include the Auto-Scaling Group name as a metric dimension:', default=False, action='store_true' ) + parser.add_argument( + '-df', '--dimensions_path', required=False, + help='Absolute path to Dimensions file', + default=None + ) parser.add_argument( '-c', '--push_constant', required=False, help='Include the FixedDimension as a metric dimension', @@ -860,6 +901,7 @@ def main(): creds_path = args.creds_path installation_method = args.installation_method push_asg = args.push_asg + dimensions_path = args.dimensions_path push_constant = args.push_constant dimension_value = args.dimension_value debug_setup = args.debug_setup @@ -908,8 +950,9 @@ def _prepare_plugin_config(plugin_config): non_interactive, region, host, proxy_name, proxy_port, enable_high_resolution_metrics, flush_interval, access_key, secret_key, - creds_path, installation_method, push_asg, - push_constant, dimension_value, debug_setup, + creds_path, installation_method, push_asg, + dimensions_path, push_constant, + dimension_value, debug_setup, debug).run() PluginConfigWriter(plugin_config).write()