Repository: weaveworks/grafanalib

Issue:
Cloudwatch datasources not supported due to Target class restrictions
There is no support for Cloudwatch since the Target class has restrictions. If you remove them, you'll be able to make Cloudwatch graphs.

Comments:

Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 808dfe3..20f0ccc 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,7 +6,7 @@ Changelog
 ===========
 
 * Added Logs panel (https://grafana.com/docs/grafana/latest/panels/visualizations/logs-panel/)
-* ...
+* Added Cloudwatch metrics datasource (https://grafana.com/docs/grafana/latest/datasources/cloudwatch/)
 
 Changes
 -------
diff --git a/docs/api/grafanalib.rst b/docs/api/grafanalib.rst
index 4638337..7ac152a 100644
--- a/docs/api/grafanalib.rst
+++ b/docs/api/grafanalib.rst
@@ -4,6 +4,14 @@ grafanalib package
 Submodules
 ----------
 
+grafanalib.cloudwatch module
+----------------------------
+
+.. automodule:: grafanalib.cloudwatch
+   :members:
+   :undoc-members:
+   :show-inheritance:
+
 grafanalib.core module
 ----------------------
 
@@ -20,6 +28,22 @@ grafanalib.elasticsearch module
    :undoc-members:
    :show-inheritance:
 
+grafanalib.formatunits module
+-----------------------------
+
+.. automodule:: grafanalib.formatunits
+   :members:
+   :undoc-members:
+   :show-inheritance:
+
+grafanalib.influxdb module
+--------------------------
+
+.. automodule:: grafanalib.influxdb
+   :members:
+   :undoc-members:
+   :show-inheritance:
+
 grafanalib.opentsdb module
 --------------------------
 
@@ -60,7 +84,6 @@ grafanalib.zabbix module
    :undoc-members:
    :show-inheritance:
 
-
 Module contents
 ---------------
 
diff --git a/grafanalib/cloudwatch.py b/grafanalib/cloudwatch.py
new file mode 100644
index 0000000..15f059d
--- /dev/null
+++ b/grafanalib/cloudwatch.py
@@ -0,0 +1,57 @@
+"""Helpers to create Cloudwatch-specific Grafana queries."""
+
+import attr
+
+from attr.validators import instance_of
+
+
+@attr.s
+class CloudwatchMetricsTarget(object):
+    """
+    Generates Cloudwatch target JSON structure.
+
+    Grafana docs on using Cloudwatch:
+    https://grafana.com/docs/grafana/latest/datasources/cloudwatch/
+
+    AWS docs on Cloudwatch metrics:
+    https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/aws-services-cloudwatch-metrics.html
+
+    :param alias: legend alias
+    :param dimensions: Cloudwatch dimensions dict
+    :param expression: Cloudwatch Metric math expressions
+    :param id: unique id
+    :param matchExact: Only show metrics that exactly match all defined dimension names.
+    :param metricName: Cloudwatch metric name
+    :param namespace: Cloudwatch namespace
+    :param period: Cloudwatch data period
+    :param refId: target reference id
+    :param region: Cloudwatch region
+    :param statistics: Cloudwatch mathematic statistic
+    """
+    alias = attr.ib(default="")
+    dimensions = attr.ib(default={}, validator=instance_of(dict))
+    expression = attr.ib(default="")
+    id = attr.ib(default="")
+    matchExact = attr.ib(default=True, validator=instance_of(bool))
+    metricName = attr.ib(default="")
+    namespace = attr.ib(default="")
+    period = attr.ib(default="")
+    refId = attr.ib(default="")
+    region = attr.ib(default="default")
+    statistics = attr.ib(default=["Average"], validator=instance_of(list))
+
+    def to_json_data(self):
+
+        return {
+            "alias": self.alias,
+            "dimensions": self.dimensions,
+            "expression": self.expression,
+            "id": self.id,
+            "matchExact": self.matchExact,
+            "metricName": self.metricName,
+            "namespace": self.namespace,
+            "period": self.period,
+            "refId": self.refId,
+            "region": self.region,
+            "statistics": self.statistics
+        }


Test patch:
diff --git a/grafanalib/tests/test_cloudwatch.py b/grafanalib/tests/test_cloudwatch.py
new file mode 100644
index 0000000..b9e91bb
--- /dev/null
+++ b/grafanalib/tests/test_cloudwatch.py
@@ -0,0 +1,25 @@
+"""Tests for Cloudwatch Datasource"""
+
+import grafanalib.core as G
+import grafanalib.cloudwatch as C
+from grafanalib import _gen
+from io import StringIO
+
+
+def test_serialization_cloudwatch_metrics_target():
+    """Serializing a graph doesn't explode."""
+    graph = G.Graph(
+        title="Lambda Duration",
+        dataSource="Cloudwatch data source",
+        targets=[
+            C.CloudwatchMetricsTarget(),
+        ],
+        id=1,
+        yAxes=G.YAxes(
+            G.YAxis(format=G.SHORT_FORMAT, label="ms"),
+            G.YAxis(format=G.SHORT_FORMAT),
+        ),
+    )
+    stream = StringIO()
+    _gen.write_dashboard(graph, stream)
+    assert stream.getvalue() != ''