tests: add an integration test

This change adds an integration test.

It need a devstack with heat/aodh/ceilometer/gnocchi setuped.

The test does the following:
* check no servers and alarms are present
* create a heat autoscaling stack with aodh alarms for gnocchi
* check that the stack creation succeed
* check the stack automatically grow according the alarm configuration
* check the gnocchi resource have been created
* delete the stack
* check everything have been deleted

This test use gabbi to talk with all API.

Change-Id: I897ef4aa359fa7b65c0f18b1999e403eb89045a7
diff --git a/ceilometer/tests/integration/__init__.py b/ceilometer/tests/integration/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ceilometer/tests/integration/__init__.py
diff --git a/ceilometer/tests/integration/gabbi/__init__.py b/ceilometer/tests/integration/gabbi/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ceilometer/tests/integration/gabbi/__init__.py
diff --git a/ceilometer/tests/integration/gabbi/gabbits-live/autoscaling.yaml b/ceilometer/tests/integration/gabbi/gabbits-live/autoscaling.yaml
new file mode 100644
index 0000000..04d7b45
--- /dev/null
+++ b/ceilometer/tests/integration/gabbi/gabbits-live/autoscaling.yaml
@@ -0,0 +1,169 @@
+defaults:
+    request_headers:
+        x-auth-token: $ENVIRON['ADMIN_TOKEN']
+
+tests:
+    - name: list alarms none
+      desc: Lists alarms, none yet exist
+      url: $ENVIRON['AODH_SERVICE_URL']/v2/alarms
+      method: GET
+      response_strings:
+          - "[]"
+
+    - name: list servers none
+      desc: List servers, none yet exists
+      url: $ENVIRON['NOVA_SERVICE_URL']/servers
+      method: GET
+      response_strings:
+          - "[]"
+
+    - name: create stack
+      desc: Create an autoscaling stack
+      url: $ENVIRON['HEAT_SERVICE_URL']/stacks
+      method: POST
+      request_headers:
+          content-type: application/json
+      data:
+          stack_name: integration_test
+          template:
+              heat_template_version: "2013-05-23"
+              description: Integration Test AutoScaling with heat+ceilometer+gnocchi+aodh
+              resources:
+                asg:
+                  type: OS::Heat::AutoScalingGroup
+                  properties:
+                    min_size: 1
+                    max_size: 3
+                    resource:
+                      type: OS::Nova::Server
+                      properties:
+                        networks:
+                          - network: "private"
+                        flavor: m1.tiny
+                        image: $ENVIRON['GLANCE_IMAGE_NAME']
+                        metadata:
+                          "metering.server_group": {get_param: "OS::stack_id"}
+                        user_data_format: RAW
+                        user_data: |
+                          #!/bin/sh
+                          echo "Loading CPU"
+                          set -v
+                          cat /dev/urandom > /dev/null
+                web_server_scaleup_policy:
+                  type: OS::Heat::ScalingPolicy
+                  properties:
+                    adjustment_type: change_in_capacity
+                    auto_scaling_group_id: {get_resource: asg}
+                    cooldown: 2
+                    scaling_adjustment: 1
+                cpu_alarm_high:
+                  type: OS::Ceilometer::GnocchiAggregationByResourcesAlarm
+                  properties:
+                    description: Scale-up if the mean CPU > 10% on 1 minute
+                    metric: cpu_util
+                    aggregation_method: mean
+                    granularity: 60.0
+                    evaluation_periods: 1
+                    threshold: 10
+                    comparison_operator: gt
+                    alarm_actions:
+                      - {get_attr: [web_server_scaleup_policy, alarm_url]}
+                    resource_type: instance
+                    query:
+                      str_replace:
+                        template: '{"=": {"server_group": "stack_id"}}'
+                        params:
+                           stack_id: {get_param: "OS::stack_id"}
+                # TODO(sileht): create some other kind of kind alarm just to ensure
+                # heat and aodh API are in sync
+      status: 201
+
+    - name: waiting for stack creation
+      desc: Wait for the second event on the stack resource, it can be a success or failure
+      url: $ENVIRON['HEAT_SERVICE_URL']/stacks/integration_test/events?resource_name=integration_test
+      redirects: true
+      method: GET
+      status: 200
+      poll:
+          count: 300
+          delay: 1
+      response_json_paths:
+          $.events[1].resource_name: integration_test
+
+    - name: control stack status
+      desc: Checks the stack have been created successfully
+      url: $ENVIRON['HEAT_SERVICE_URL']/stacks/integration_test
+      redirects: true
+      method: GET
+      status: 200
+      response_json_paths:
+          $.stack.stack_status: "CREATE_COMPLETE"
+
+    - name: list servers
+      desc: Wait the autoscaling stack grow to three servers
+      url: $ENVIRON['NOVA_SERVICE_URL']/servers/detail
+      method: GET
+      poll:
+          count: 1200
+          delay: 1
+      response_json_paths:
+          $.servers[0].metadata.'metering.server_group': $RESPONSE['$.stack.id']
+          $.servers[1].metadata.'metering.server_group': $RESPONSE['$.stack.id']
+          $.servers[2].metadata.'metering.server_group': $RESPONSE['$.stack.id']
+          $.servers[0].status: ACTIVE
+          $.servers[1].status: ACTIVE
+          $.servers[2].status: ACTIVE
+
+    - name: check gnocchi resources
+      desc: Check the gnocchi resources for this three servers exists
+      url: $ENVIRON['GNOCCHI_SERVICE_URL']/v1/resource/instance
+      method: GET
+      response_strings:
+          - '"id": "$RESPONSE["$.servers[0].id"]"'
+          - '"id": "$RESPONSE["$.servers[1].id"]"'
+          - '"id": "$RESPONSE["$.servers[2].id"]"'
+
+    - name: check alarm
+      desc: Check the aodh alarm and its state
+      url: $ENVIRON['AODH_SERVICE_URL']/v2/alarms
+      method: GET
+      response_strings:
+          - "integration_test-cpu_alarm_high-"
+      response_json_paths:
+          $[0].state: alarm
+
+    - name: get stack location
+      desc: Get the stack location
+      url: $ENVIRON['HEAT_SERVICE_URL']/stacks/integration_test
+      method: GET
+      status: 302
+
+    - name: delete stack
+      desc: Delete the stack
+      url: $LOCATION
+      method: DELETE
+      status: 204
+
+    - name: get deleted stack
+      desc: Check the stack have been deleted
+      url: $ENVIRON['HEAT_SERVICE_URL']/stacks/integration_test
+      redirects: true
+      method: GET
+      poll:
+          count: 240
+          delay: 1
+      status: 404
+
+    - name: list alarms deleted
+      desc: List alarms, no more exist
+      url: $ENVIRON['AODH_SERVICE_URL']/v2/alarms
+      method: GET
+      response_strings:
+          - "[]"
+
+    - name: list servers deleted
+      desc: List servers, no more exists
+      url: $ENVIRON['NOVA_SERVICE_URL']/servers
+      method: GET
+      response_strings:
+          - "[]"
diff --git a/ceilometer/tests/integration/gabbi/test_gabbi_live.py b/ceilometer/tests/integration/gabbi/test_gabbi_live.py
new file mode 100644
index 0000000..b347b55
--- /dev/null
+++ b/ceilometer/tests/integration/gabbi/test_gabbi_live.py
@@ -0,0 +1,40 @@
+#
+# Copyright 2015 Red Hat. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""A test module to exercise the Gnocchi API with gabbi."""
+
+import os
+
+from gabbi import driver
+
+
+TESTS_DIR = 'gabbits-live'
+
+
+def load_tests(loader, tests, pattern):
+    """Provide a TestSuite to the discovery process."""
+    NEEDED_ENV = ["AODH_SERVICE_URL", "GNOCCHI_SERVICE_URL",
+                  "HEAT_SERVICE_URL", "NOVA_SERVICE_URL",
+                  "GLANCE_IMAGE_NAME", "ADMIN_TOKEN"]
+
+    for env_variable in NEEDED_ENV:
+        if not os.getenv(env_variable):
+            if os.getenv("GABBI_LIVE_FAIL_IF_NO_TEST"):
+                raise RuntimeError('%s is not set' % env_variable)
+            else:
+                return
+
+    test_dir = os.path.join(os.path.dirname(__file__), TESTS_DIR)
+    return driver.build_tests(test_dir, loader, host="localhost", port=8041)
diff --git a/ceilometer/tests/integration/hooks/post_test_hook.sh b/ceilometer/tests/integration/hooks/post_test_hook.sh
new file mode 100755
index 0000000..cb241e7
--- /dev/null
+++ b/ceilometer/tests/integration/hooks/post_test_hook.sh
@@ -0,0 +1,61 @@
+#!/bin/bash -xe
+
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+# This script is executed inside post_test_hook function in devstack gate.
+
+function generate_testr_results {
+    if [ -f .testrepository/0 ]; then
+        sudo .tox/functional/bin/testr last --subunit > $WORKSPACE/testrepository.subunit
+        sudo mv $WORKSPACE/testrepository.subunit $BASE/logs/testrepository.subunit
+        sudo .tox/functional/bin/python /usr/local/jenkins/slave_scripts/subunit2html.py $BASE/logs/testrepository.subunit $BASE/logs/testr_results.html
+        sudo gzip -9 $BASE/logs/testrepository.subunit
+        sudo gzip -9 $BASE/logs/testr_results.html
+        sudo chown jenkins:jenkins $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz
+        sudo chmod a+r $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz
+    fi
+}
+
+# If we're running in the gate find our keystone endpoint to give to
+# gabbi tests and do a chown. Otherwise the existing environment
+# should provide URL and TOKEN.
+if [ -f $BASE/new/devstack ]; then
+    export CEILOMETER_DIR="$BASE/new/ceilometer"
+    JENKINS_USER=jenkins
+    sudo chown -R jenkins:stack $CEILOMETER_DIR
+    source $BASE/new/devstack/openrc admin admin
+    # Go to the ceilometer dir
+    cd $CEILOMETER_DIR
+fi
+
+openstack catalog list
+export AODH_SERVICE_URL=$(openstack catalog show alarming -c endpoints -f value | awk '/publicURL/{print $2}')
+export GNOCCHI_SERVICE_URL=$(openstack catalog show metric -c endpoints -f value | awk '/publicURL/{print $2}')
+export HEAT_SERVICE_URL=$(openstack catalog show orchestration -c endpoints -f value | awk '/publicURL/{print $2}')
+export NOVA_SERVICE_URL=$(openstack catalog show compute -c endpoints -f value | awk '/publicURL/{print $2}')
+export GLANCE_IMAGE_NAME=$(openstack image list | awk '/ cirros.*uec /{print $4}')
+export ADMIN_TOKEN=$(openstack token issue -c id -f value)
+
+# Run tests
+echo "Running telemetry integration test suite"
+set +e
+
+sudo -E -H -u ${JENKINS_USER:-${USER}} tox -eintegration
+EXIT_CODE=$?
+set -e
+
+# Collect and parse result
+if [ -n "$CEILOMETER_DIR" ]; then
+    generate_testr_results
+fi
+exit $EXIT_CODE