Fix work of udp publisher

* Signature is appended also to udp messages
 * All methods for convert from sample to message are moved to publisher/utils.py
 * In configs metering_secret is moved from group publisher_rpc to publisher
 * Changed tests for udp publisher

Fixes: bug #1259171

Change-Id: Ic7727c69d4be6d17ff00f21e323341efd57122a7
This commit is contained in:
Ilya Tyaptin 2013-12-17 17:55:39 +04:00
parent e564c1e395
commit cdab1401dc
28 changed files with 361 additions and 327 deletions

View File

@ -77,10 +77,6 @@ class CollectorService(service.DispatchedService, rpc_service.Service):
LOG.warn(_("UDP: Cannot decode data sent by %s"), str(source))
else:
try:
sample['counter_name'] = sample['name']
sample['counter_volume'] = sample['volume']
sample['counter_unit'] = sample['unit']
sample['counter_type'] = sample['type']
LOG.debug(_("UDP: Storing %s"), str(sample))
self.dispatcher_manager.map_method('record_metering_data',
sample)

View File

@ -20,7 +20,7 @@ from ceilometer import dispatcher
from ceilometer.openstack.common.gettextutils import _ # noqa
from ceilometer.openstack.common import log
from ceilometer.openstack.common import timeutils
from ceilometer.publisher import rpc as publisher_rpc
from ceilometer.publisher import utils as publisher_utils
from ceilometer import storage
LOG = log.getLogger(__name__)
@ -54,9 +54,9 @@ class DatabaseDispatcher(dispatcher.Base):
'resource_id': meter['resource_id'],
'timestamp': meter.get('timestamp', 'NO TIMESTAMP'),
'counter_volume': meter['counter_volume']}))
if publisher_rpc.verify_signature(
if publisher_utils.verify_signature(
meter,
self.conf.publisher_rpc.metering_secret):
self.conf.publisher.metering_secret):
try:
# Convert the timestamp to a datetime instance.
# Storage engines are responsible for converting

View File

@ -18,8 +18,7 @@
"""Publish a sample using the preferred RPC mechanism.
"""
import hashlib
import hmac
import itertools
import operator
import urlparse
@ -30,7 +29,7 @@ from ceilometer.openstack.common.gettextutils import _ # noqa
from ceilometer.openstack.common import log
from ceilometer.openstack.common import rpc
from ceilometer import publisher
from ceilometer import utils
from ceilometer.publisher import utils
LOG = log.getLogger(__name__)
@ -41,12 +40,6 @@ METER_PUBLISH_OPTS = [
help='the topic ceilometer uses for metering messages',
deprecated_group="DEFAULT",
),
cfg.StrOpt('metering_secret',
secret=True,
default='change this or be hacked',
help='Secret value for signing metering messages',
deprecated_group="DEFAULT",
),
]
@ -91,51 +84,6 @@ def override_backend_retry_config(value):
cfg.CONF.set_override('rabbit_max_retries', value)
def compute_signature(message, secret):
"""Return the signature for a message dictionary.
"""
digest_maker = hmac.new(secret, '', hashlib.sha256)
for name, value in utils.recursive_keypairs(message):
if name == 'message_signature':
# Skip any existing signature value, which would not have
# been part of the original message.
continue
digest_maker.update(name)
digest_maker.update(unicode(value).encode('utf-8'))
return digest_maker.hexdigest()
def verify_signature(message, secret):
"""Check the signature in the message against the value computed
from the rest of the contents.
"""
old_sig = message.get('message_signature')
new_sig = compute_signature(message, secret)
return new_sig == old_sig
def meter_message_from_counter(sample, secret):
"""Make a metering message ready to be published or stored.
Returns a dictionary containing a metering message
for a notification message and a Sample instance.
"""
msg = {'source': sample.source,
'counter_name': sample.name,
'counter_type': sample.type,
'counter_unit': sample.unit,
'counter_volume': sample.volume,
'user_id': sample.user_id,
'project_id': sample.project_id,
'resource_id': sample.resource_id,
'timestamp': sample.timestamp,
'resource_metadata': sample.resource_metadata,
'message_id': sample.id,
}
msg['message_signature'] = compute_signature(msg, secret)
return msg
class RPCPublisher(publisher.PublisherBase):
def __init__(self, parsed_url):
@ -175,9 +123,9 @@ class RPCPublisher(publisher.PublisherBase):
"""
meters = [
meter_message_from_counter(
utils.meter_message_from_counter(
sample,
cfg.CONF.publisher_rpc.metering_secret)
cfg.CONF.publisher.metering_secret)
for sample in samples
]

View File

@ -2,7 +2,8 @@
#
# Copyright © 2013 eNovance
#
# Author: Julien Danjou <julien@danjou.info>
# Author: Julien Danjou <julien@danjou.info>,
# Tyaptin Ilya <ityaptin@mirantis.com>
#
# 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
@ -27,6 +28,7 @@ from ceilometer.openstack.common.gettextutils import _ # noqa
from ceilometer.openstack.common import log
from ceilometer.openstack.common import network_utils
from ceilometer import publisher
from ceilometer.publisher import utils
cfg.CONF.import_opt('udp_port', 'ceilometer.collector',
group='collector')
@ -35,7 +37,6 @@ LOG = log.getLogger(__name__)
class UDPPublisher(publisher.PublisherBase):
def __init__(self, parsed_url):
self.host, self.port = network_utils.parse_host_port(
parsed_url.netloc,
@ -51,7 +52,9 @@ class UDPPublisher(publisher.PublisherBase):
"""
for sample in samples:
msg = sample.as_dict()
msg = utils.meter_message_from_counter(
sample,
cfg.CONF.publisher.metering_secret)
host = self.host
port = self.port
LOG.debug(_("Publishing sample %(msg)s over UDP to "

View File

@ -0,0 +1,93 @@
# -*- encoding: utf-8 -*-
#
# Copyright © 2012 New Dream Network, LLC (DreamHost)
#
# Author: Doug Hellmann <doug.hellmann@dreamhost.com>
# Tyaptin Ilya <ityaptin@mirantis.com>
#
# 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.
"""Utils for publishers
"""
import hashlib
import hmac
from oslo.config import cfg
from ceilometer import utils
METER_PUBLISH_OPTS = [
cfg.StrOpt('metering_secret',
secret=True,
default='change this or be hacked',
help='Secret value for signing metering messages',
deprecated_opts=[cfg.DeprecatedOpt("metering_secret",
"DEFAULT"),
cfg.DeprecatedOpt("metering_secret",
"publisher_rpc")]
),
]
def register_opts(config):
"""Register the options for publishing metering messages.
"""
config.register_opts(METER_PUBLISH_OPTS, group="publisher")
register_opts(cfg.CONF)
def compute_signature(message, secret):
"""Return the signature for a message dictionary.
"""
digest_maker = hmac.new(secret, '', hashlib.sha256)
for name, value in utils.recursive_keypairs(message):
if name == 'message_signature':
# Skip any existing signature value, which would not have
# been part of the original message.
continue
digest_maker.update(name)
digest_maker.update(unicode(value).encode('utf-8'))
return digest_maker.hexdigest()
def verify_signature(message, secret):
"""Check the signature in the message against the value computed
from the rest of the contents.
"""
old_sig = message.get('message_signature')
new_sig = compute_signature(message, secret)
return new_sig == old_sig
def meter_message_from_counter(sample, secret):
"""Make a metering message ready to be published or stored.
Returns a dictionary containing a metering message
for a notification message and a Sample instance.
"""
msg = {'source': sample.source,
'counter_name': sample.name,
'counter_type': sample.type,
'counter_unit': sample.unit,
'counter_volume': sample.volume,
'user_id': sample.user_id,
'project_id': sample.project_id,
'resource_id': sample.resource_id,
'timestamp': sample.timestamp,
'resource_metadata': sample.resource_metadata,
'message_id': sample.id,
}
msg['message_signature'] = compute_signature(msg, secret)
return msg

View File

@ -22,7 +22,7 @@
import datetime
import testscenarios
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer.tests import api as tests_api
@ -77,9 +77,9 @@ class TestListEvents(tests_api.TestBase,
source='source1',
),
]:
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
cnt,
self.CONF.publisher_rpc.metering_secret)
self.CONF.publisher.metering_secret)
self.conn.record_metering_data(msg)
def test_empty_project(self):

View File

@ -23,7 +23,7 @@ import datetime
import logging
import testscenarios
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer.tests import api as tests_api
@ -108,9 +108,9 @@ class TestListMeters(tests_api.TestBase,
resource_metadata={'display_name': 'test-server',
'tag': 'four.sample'},
source='test_list_resources')]:
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
cnt,
self.CONF.publisher_rpc.metering_secret)
self.CONF.publisher.metering_secret)
self.conn.record_metering_data(msg)
def test_list_meters(self):

View File

@ -23,7 +23,7 @@ import datetime
import logging
import testscenarios
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer.tests import api as tests_api
@ -60,9 +60,9 @@ class TestListProjects(tests_api.TestBase,
'tag': 'self.sample'},
source='test_list_projects',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
sample1,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -79,9 +79,9 @@ class TestListProjects(tests_api.TestBase,
'tag': 'self.sample2'},
source='test_list_users',
)
msg2 = rpc.meter_message_from_counter(
msg2 = utils.meter_message_from_counter(
sample2,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg2)

View File

@ -23,7 +23,7 @@ import datetime
import logging
import testscenarios
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer.tests import api as tests_api
@ -101,9 +101,9 @@ class TestListResourcesBase(tests_api.TestBase,
'tag': 'self.sample4'},
source='test_list_resources',
)]:
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
cnt,
self.CONF.publisher_rpc.metering_secret)
self.CONF.publisher.metering_secret)
self.conn.record_metering_data(msg)

View File

@ -23,7 +23,7 @@ import datetime
import logging
import testscenarios
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer.tests import api as tests_api
@ -62,9 +62,9 @@ class TestListUsers(tests_api.TestBase,
},
source='test_list_users',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
sample1,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -82,9 +82,9 @@ class TestListUsers(tests_api.TestBase,
},
source='not-test',
)
msg2 = rpc.meter_message_from_counter(
msg2 = utils.meter_message_from_counter(
sample2,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg2)

View File

@ -22,7 +22,7 @@
import datetime
import testscenarios
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer.tests import api as tests_api
@ -51,9 +51,9 @@ class TestMaxProjectVolume(tests_api.TestBase,
},
source='source1',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
s,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)

View File

@ -21,7 +21,7 @@
import datetime
import testscenarios
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer.tests import api as tests_api
@ -50,9 +50,9 @@ class TestMaxResourceVolume(tests_api.TestBase,
},
source='source1',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
s,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)

View File

@ -22,7 +22,7 @@
import datetime
import testscenarios
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer.tests import api as tests_api
@ -51,9 +51,9 @@ class TestSumProjectVolume(tests_api.TestBase,
},
source='source1',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
s,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)

View File

@ -22,7 +22,7 @@
import datetime
import testscenarios
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer.tests import api as tests_api
@ -51,9 +51,9 @@ class TestSumResourceVolume(tests_api.TestBase,
},
source='source1',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
s,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)

View File

@ -25,7 +25,7 @@ import testscenarios
from ceilometer.api import acl
from ceilometer.api.controllers import v2 as v2_api
from ceilometer.openstack.common import timeutils
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer.tests.api.v2 import FunctionalTest
from ceilometer.tests import db as tests_db
@ -104,9 +104,9 @@ class TestAPIACL(FunctionalTest,
resource_metadata={'display_name': 'test-server',
'tag': 'self.sample4'},
source='test_source')]:
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
cnt,
self.CONF.publisher_rpc.metering_secret)
self.CONF.publisher.metering_secret)
self.conn.record_metering_data(msg)
def get_json(self, path, expect_errors=False, headers=None,

View File

@ -24,7 +24,7 @@ import logging
import testscenarios
import webtest.app
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer.tests.api.v2 import FunctionalTest
from ceilometer.tests import db as tests_db
@ -56,9 +56,9 @@ class TestListEvents(FunctionalTest,
},
source='test_source',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
self.sample1,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -76,9 +76,9 @@ class TestListEvents(FunctionalTest,
},
source='source2',
)
msg2 = rpc.meter_message_from_counter(
msg2 = utils.meter_message_from_counter(
self.sample2,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg2)

View File

@ -24,7 +24,7 @@ import datetime
import logging
import testscenarios
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer.tests.api.v2 import FunctionalTest
from ceilometer.tests import db as tests_db
@ -128,9 +128,9 @@ class TestListMeters(FunctionalTest,
'util': 0.58,
'is_public': True},
source='test_source1')]:
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
cnt,
self.CONF.publisher_rpc.metering_secret)
self.CONF.publisher.metering_secret)
self.conn.record_metering_data(msg)
def test_list_meters(self):

View File

@ -23,8 +23,9 @@ import json
import logging
import testscenarios
from ceilometer.openstack.common import timeutils
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer.tests.api.v2 import FunctionalTest
from ceilometer.tests import db as tests_db
@ -66,9 +67,9 @@ class TestListResources(FunctionalTest,
resource_metadata=None,
source='test',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
sample1,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -95,9 +96,9 @@ class TestListResources(FunctionalTest,
},
source='test',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
sample1,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -115,9 +116,9 @@ class TestListResources(FunctionalTest,
},
source='test',
)
msg2 = rpc.meter_message_from_counter(
msg2 = utils.meter_message_from_counter(
sample2,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg2)
@ -148,9 +149,9 @@ class TestListResources(FunctionalTest,
},
source='test',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
datapoint,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -173,9 +174,9 @@ class TestListResources(FunctionalTest,
},
source='test',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
sample1,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -193,9 +194,9 @@ class TestListResources(FunctionalTest,
},
source='test',
)
msg2 = rpc.meter_message_from_counter(
msg2 = utils.meter_message_from_counter(
sample2,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg2)
@ -217,9 +218,9 @@ class TestListResources(FunctionalTest,
},
source='test_list_resources',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
sample1,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -237,9 +238,9 @@ class TestListResources(FunctionalTest,
},
source='not-test',
)
msg2 = rpc.meter_message_from_counter(
msg2 = utils.meter_message_from_counter(
sample2,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg2)
@ -266,9 +267,9 @@ class TestListResources(FunctionalTest,
},
source='test_list_resources',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
sample1,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -286,9 +287,9 @@ class TestListResources(FunctionalTest,
},
source='test_list_resources',
)
msg2 = rpc.meter_message_from_counter(
msg2 = utils.meter_message_from_counter(
sample2,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg2)
@ -319,9 +320,9 @@ class TestListResources(FunctionalTest,
},
source='test_list_resources',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
sample1,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -339,9 +340,9 @@ class TestListResources(FunctionalTest,
},
source='not-test',
)
msg2 = rpc.meter_message_from_counter(
msg2 = utils.meter_message_from_counter(
sample2,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg2)
@ -366,9 +367,9 @@ class TestListResources(FunctionalTest,
},
source='test_list_resources',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
sample1,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -386,9 +387,9 @@ class TestListResources(FunctionalTest,
},
source='not-test',
)
msg2 = rpc.meter_message_from_counter(
msg2 = utils.meter_message_from_counter(
sample2,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg2)
@ -413,9 +414,9 @@ class TestListResources(FunctionalTest,
},
source='not-test',
)
msg2 = rpc.meter_message_from_counter(
msg2 = utils.meter_message_from_counter(
sample1,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg2)
@ -440,9 +441,9 @@ class TestListResources(FunctionalTest,
},
source='not-test',
)
msg2 = rpc.meter_message_from_counter(
msg2 = utils.meter_message_from_counter(
sample1,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg2)
@ -469,9 +470,9 @@ class TestListResources(FunctionalTest,
},
source='test',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
sample1,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -499,9 +500,9 @@ class TestListResources(FunctionalTest,
},
source='test_list_resources',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
sample1,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)

View File

@ -21,7 +21,7 @@ import datetime
import testscenarios
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer.tests.api.v2 import FunctionalTest
from ceilometer.tests import db as tests_db
@ -51,9 +51,9 @@ class TestMaxProjectVolume(FunctionalTest,
},
source='source1',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
s,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -149,9 +149,9 @@ class TestMaxResourceVolume(FunctionalTest,
},
source='source1',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
s,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -270,9 +270,9 @@ class TestSumProjectVolume(FunctionalTest,
},
source='source1',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
s,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -370,9 +370,9 @@ class TestSumResourceVolume(FunctionalTest,
},
source='source1',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
s,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -527,9 +527,9 @@ class TestGroupByInstance(FunctionalTest,
'event': test_sample['metadata_event'], },
source=test_sample['source'],
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
c,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -1285,9 +1285,9 @@ class TestGroupBySource(FunctionalTest,
'event': test_sample['metadata_event'], },
source=test_sample['source'],
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
c,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)

View File

@ -22,7 +22,7 @@ import mock
from ceilometer.dispatcher import database
from ceilometer.openstack.common.fixture import config
from ceilometer.openstack.common import test
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
class TestDispatcherDB(test.BaseTestCase):
@ -38,9 +38,9 @@ class TestDispatcherDB(test.BaseTestCase):
'resource_id': self.id(),
'counter_volume': 1,
}
msg['message_signature'] = rpc.compute_signature(
msg['message_signature'] = utils.compute_signature(
msg,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
with mock.patch.object(self.dispatcher.storage_conn,
@ -76,9 +76,9 @@ class TestDispatcherDB(test.BaseTestCase):
'counter_volume': 1,
'timestamp': '2012-07-02T13:53:40Z',
}
msg['message_signature'] = rpc.compute_signature(
msg['message_signature'] = utils.compute_signature(
msg,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
expected = msg.copy()
@ -96,9 +96,9 @@ class TestDispatcherDB(test.BaseTestCase):
'counter_volume': 1,
'timestamp': '2012-09-30T15:31:50.262-08:00',
}
msg['message_signature'] = rpc.compute_signature(
msg['message_signature'] = utils.compute_signature(
msg,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
expected = msg.copy()

View File

@ -22,7 +22,7 @@ import tempfile
from ceilometer.dispatcher import file
from ceilometer.openstack.common.fixture import config
from ceilometer.openstack.common import test
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
class TestDispatcherFile(test.BaseTestCase):
@ -53,9 +53,9 @@ class TestDispatcherFile(test.BaseTestCase):
'resource_id': self.id(),
'counter_volume': 1,
}
msg['message_signature'] = rpc.compute_signature(
msg['message_signature'] = utils.compute_signature(
msg,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
# The record_metering_data method should exist and not produce errors.
@ -85,9 +85,9 @@ class TestDispatcherFile(test.BaseTestCase):
'resource_id': self.id(),
'counter_volume': 1,
}
msg['message_signature'] = rpc.compute_signature(
msg['message_signature'] = utils.compute_signature(
msg,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
# The record_metering_data method should exist and not produce errors.

View File

@ -25,140 +25,13 @@ import fixtures
import mock
from ceilometer.openstack.common.fixture import config
from ceilometer.openstack.common import jsonutils
from ceilometer.openstack.common import network_utils
from ceilometer.openstack.common import test
from ceilometer.publisher import rpc
from ceilometer import sample
class TestSignature(test.BaseTestCase):
def test_compute_signature_change_key(self):
sig1 = rpc.compute_signature({'a': 'A', 'b': 'B'},
'not-so-secret')
sig2 = rpc.compute_signature({'A': 'A', 'b': 'B'},
'not-so-secret')
self.assertNotEqual(sig1, sig2)
def test_compute_signature_change_value(self):
sig1 = rpc.compute_signature({'a': 'A', 'b': 'B'},
'not-so-secret')
sig2 = rpc.compute_signature({'a': 'a', 'b': 'B'},
'not-so-secret')
self.assertNotEqual(sig1, sig2)
def test_compute_signature_same(self):
sig1 = rpc.compute_signature({'a': 'A', 'b': 'B'},
'not-so-secret')
sig2 = rpc.compute_signature({'a': 'A', 'b': 'B'},
'not-so-secret')
self.assertEqual(sig1, sig2)
def test_compute_signature_signed(self):
data = {'a': 'A', 'b': 'B'}
sig1 = rpc.compute_signature(data, 'not-so-secret')
data['message_signature'] = sig1
sig2 = rpc.compute_signature(data, 'not-so-secret')
self.assertEqual(sig1, sig2)
def test_compute_signature_use_configured_secret(self):
data = {'a': 'A', 'b': 'B'}
sig1 = rpc.compute_signature(data, 'not-so-secret')
sig2 = rpc.compute_signature(data, 'different-value')
self.assertNotEqual(sig1, sig2)
def test_verify_signature_signed(self):
data = {'a': 'A', 'b': 'B'}
sig1 = rpc.compute_signature(data, 'not-so-secret')
data['message_signature'] = sig1
self.assertTrue(rpc.verify_signature(data, 'not-so-secret'))
def test_verify_signature_unsigned(self):
data = {'a': 'A', 'b': 'B'}
self.assertFalse(rpc.verify_signature(data, 'not-so-secret'))
def test_verify_signature_incorrect(self):
data = {'a': 'A', 'b': 'B',
'message_signature': 'Not the same'}
self.assertFalse(rpc.verify_signature(data, 'not-so-secret'))
def test_verify_signature_nested(self):
data = {'a': 'A',
'b': 'B',
'nested': {'a': 'A',
'b': 'B',
},
}
data['message_signature'] = rpc.compute_signature(
data,
'not-so-secret')
self.assertTrue(rpc.verify_signature(data, 'not-so-secret'))
def test_verify_signature_nested_list_of_dict(self):
small = 1
big = 1 << 64
nested = {small: 99, big: 42}
data = {'a': 'A',
'b': 'B',
'nested': {'list': [nested]}}
data['message_signature'] = rpc.compute_signature(
data,
'not-so-secret')
# the keys 1 and 1<<64 cause a hash collision on 64bit platforms
data['nested']['list'] = [{big: 42, small: 99}]
self.assertTrue(rpc.verify_signature(data, 'not-so-secret'))
def test_verify_signature_nested_json(self):
data = {'a': 'A',
'b': 'B',
'nested': {'a': 'A',
'b': 'B',
'c': ('c',),
'd': ['d']
},
}
data['message_signature'] = rpc.compute_signature(
data,
'not-so-secret')
jsondata = jsonutils.loads(jsonutils.dumps(data))
self.assertTrue(rpc.verify_signature(jsondata, 'not-so-secret'))
class TestCounter(test.BaseTestCase):
TEST_COUNTER = sample.Sample(name='name',
type='typ',
unit='',
volume=1,
user_id='user',
project_id='project',
resource_id=2,
timestamp='today',
resource_metadata={'key': 'value'},
source='rpc')
def test_meter_message_from_counter_signed(self):
msg = rpc.meter_message_from_counter(self.TEST_COUNTER,
'not-so-secret')
self.assertIn('message_signature', msg)
def test_meter_message_from_counter_field(self):
def compare(f, c, msg_f, msg):
self.assertEqual(msg, c)
msg = rpc.meter_message_from_counter(self.TEST_COUNTER,
'not-so-secret')
name_map = {'name': 'counter_name',
'type': 'counter_type',
'unit': 'counter_unit',
'volume': 'counter_volume'}
for f in self.TEST_COUNTER._fields:
msg_f = name_map.get(f, f)
yield compare, f, getattr(self.TEST_COUNTER, f), msg_f, msg[msg_f]
class TestPublish(test.BaseTestCase):
test_data = [
sample.Sample(
name='test',
@ -233,8 +106,8 @@ class TestPublish(test.BaseTestCase):
self.published = []
self.rpc_unreachable = False
self.useFixture(fixtures.MonkeyPatch(
"ceilometer.openstack.common.rpc.cast",
self.faux_cast))
"ceilometer.openstack.common.rpc.cast",
self.faux_cast))
def test_published(self):
publisher = rpc.RPCPublisher(
@ -294,15 +167,15 @@ class TestPublish(test.BaseTestCase):
def faux_cast_wait(context, topic, msg):
self.useFixture(fixtures.MonkeyPatch(
"ceilometer.openstack.common.rpc.cast",
faux_cast_go))
"ceilometer.openstack.common.rpc.cast",
faux_cast_go))
# Sleep to simulate concurrency and allow other threads to work
eventlet.sleep(0)
self.published.append((topic, msg))
self.useFixture(fixtures.MonkeyPatch(
"ceilometer.openstack.common.rpc.cast",
faux_cast_wait))
"ceilometer.openstack.common.rpc.cast",
faux_cast_wait))
publisher = rpc.RPCPublisher(network_utils.urlsplit('rpc://'))
job1 = eventlet.spawn(publisher.publish_samples, None, self.test_data)

View File

@ -27,6 +27,7 @@ from ceilometer.openstack.common.fixture import config
from ceilometer.openstack.common import network_utils
from ceilometer.openstack.common import test
from ceilometer.publisher import udp
from ceilometer.publisher import utils
from ceilometer import sample
@ -34,7 +35,6 @@ COUNTER_SOURCE = 'testsource'
class TestUDPPublisher(test.BaseTestCase):
test_data = [
sample.Sample(
name='test',
@ -102,14 +102,17 @@ class TestUDPPublisher(test.BaseTestCase):
def _fake_socket_socket(family, type):
def record_data(msg, dest):
published.append((msg, dest))
udp_socket = mock.Mock()
udp_socket.sendto = record_data
return udp_socket
return _fake_socket_socket
def setUp(self):
super(TestUDPPublisher, self).setUp()
self.CONF = self.useFixture(config.Config()).conf
self.CONF.publisher.metering_secret = 'not-so-secret'
def test_published(self):
self.data_sent = []
@ -134,7 +137,11 @@ class TestUDPPublisher(test.BaseTestCase):
# Check that counters are equal
self.assertEqual(sorted(sent_counters),
sorted([dict(d.as_dict()) for d in self.test_data]))
sorted(
[utils.meter_message_from_counter(
d,
"not-so-secret")
for d in self.test_data]))
@staticmethod
def _raise_ioerror(*args):

View File

@ -0,0 +1,103 @@
# -*- encoding: utf-8 -*-
#
# Copyright © 2012 New Dream Network, LLC (DreamHost)
#
# Author: Doug Hellmann <doug.hellmann@dreamhost.com>
# Julien Danjou <julien@danjou.info>
# Tyaptin Ilya <ityaptin@mirantis.com>
#
# 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.
"""Tests for ceilometer/publisher/utils.py
"""
from ceilometer.openstack.common import jsonutils
from ceilometer.openstack.common import test
from ceilometer.publisher import utils
class TestSignature(test.BaseTestCase):
def test_compute_signature_change_key(self):
sig1 = utils.compute_signature({'a': 'A', 'b': 'B'},
'not-so-secret')
sig2 = utils.compute_signature({'A': 'A', 'b': 'B'},
'not-so-secret')
self.assertNotEqual(sig1, sig2)
def test_compute_signature_change_value(self):
sig1 = utils.compute_signature({'a': 'A', 'b': 'B'},
'not-so-secret')
sig2 = utils.compute_signature({'a': 'a', 'b': 'B'},
'not-so-secret')
self.assertNotEqual(sig1, sig2)
def test_compute_signature_same(self):
sig1 = utils.compute_signature({'a': 'A', 'b': 'B'},
'not-so-secret')
sig2 = utils.compute_signature({'a': 'A', 'b': 'B'},
'not-so-secret')
self.assertEqual(sig1, sig2)
def test_compute_signature_signed(self):
data = {'a': 'A', 'b': 'B'}
sig1 = utils.compute_signature(data, 'not-so-secret')
data['message_signature'] = sig1
sig2 = utils.compute_signature(data, 'not-so-secret')
self.assertEqual(sig1, sig2)
def test_compute_signature_use_configured_secret(self):
data = {'a': 'A', 'b': 'B'}
sig1 = utils.compute_signature(data, 'not-so-secret')
sig2 = utils.compute_signature(data, 'different-value')
self.assertNotEqual(sig1, sig2)
def test_verify_signature_signed(self):
data = {'a': 'A', 'b': 'B'}
sig1 = utils.compute_signature(data, 'not-so-secret')
data['message_signature'] = sig1
self.assertTrue(utils.verify_signature(data, 'not-so-secret'))
def test_verify_signature_unsigned(self):
data = {'a': 'A', 'b': 'B'}
self.assertFalse(utils.verify_signature(data, 'not-so-secret'))
def test_verify_signature_incorrect(self):
data = {'a': 'A', 'b': 'B',
'message_signature': 'Not the same'}
self.assertFalse(utils.verify_signature(data, 'not-so-secret'))
def test_verify_signature_nested(self):
data = {'a': 'A',
'b': 'B',
'nested': {'a': 'A',
'b': 'B',
},
}
data['message_signature'] = utils.compute_signature(
data,
'not-so-secret')
self.assertTrue(utils.verify_signature(data, 'not-so-secret'))
def test_verify_signature_nested_json(self):
data = {'a': 'A',
'b': 'B',
'nested': {'a': 'A',
'b': 'B',
'c': ('c',),
'd': ['d']
},
}
data['message_signature'] = utils.compute_signature(
data,
'not-so-secret')
jsondata = jsonutils.loads(jsonutils.dumps(data))
self.assertTrue(utils.verify_signature(jsondata, 'not-so-secret'))

View File

@ -28,7 +28,7 @@ import copy
import datetime
from mock import patch
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer.storage import base
from ceilometer.storage import impl_mongodb
@ -180,7 +180,7 @@ class CompatibilityTest(test_storage_scenarios.DBTestBase,
source='test',
)
self.counters.append(c)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
c,
secret='not-so-secret')
self.conn.record_metering_data(self.conn, msg)

View File

@ -24,7 +24,7 @@ import datetime
import testscenarios
from ceilometer.openstack.common import timeutils
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer import storage
from ceilometer.storage import base
@ -51,8 +51,8 @@ class DBTestBase(tests_db.TestBase):
timestamp=timestamp,
resource_metadata=metadata, source=source
)
msg = rpc.meter_message_from_counter(
s, self.CONF.publisher_rpc.metering_secret
msg = utils.meter_message_from_counter(
s, self.CONF.publisher.metering_secret
)
self.conn.record_metering_data(msg)
return msg
@ -730,7 +730,7 @@ class StatisticsTest(DBTestBase,
},
source='test',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
c,
secret='not-so-secret',
)
@ -750,7 +750,7 @@ class StatisticsTest(DBTestBase,
},
source='test',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
c,
secret='not-so-secret',
)
@ -971,9 +971,9 @@ class StatisticsGroupByTest(DBTestBase,
'event': test_sample['metadata_event'], },
source=test_sample['source'],
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
c,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -1835,9 +1835,9 @@ class CounterDataTypeTest(DBTestBase,
resource_metadata={},
source='test-1',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
c,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -1854,9 +1854,9 @@ class CounterDataTypeTest(DBTestBase,
resource_metadata={},
source='test-1',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
c,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -1872,9 +1872,9 @@ class CounterDataTypeTest(DBTestBase,
resource_metadata={},
source='test-1',
)
msg = rpc.meter_message_from_counter(
msg = utils.meter_message_from_counter(
c,
self.CONF.publisher_rpc.metering_secret,
self.CONF.publisher.metering_secret,
)
self.conn.record_metering_data(msg)
@ -2356,6 +2356,6 @@ class BigIntegerTest(tests_db.TestBase,
resource_id='resource-id',
timestamp=datetime.datetime.utcnow(),
resource_metadata=metadata)
msg = rpc.meter_message_from_counter(
s, self.CONF.publisher_rpc.metering_secret)
msg = utils.meter_message_from_counter(
s, self.CONF.publisher.metering_secret)
self.conn.record_metering_data(msg)

View File

@ -877,6 +877,18 @@
#store_events=false
[publisher]
#
# Options defined in ceilometer.publisher.utils
#
# Secret value for signing metering messages (string value)
# Deprecated group/name - [DEFAULT]/metering_secret
# Deprecated group/name - [publisher_rpc]/metering_secret
#metering_secret=change this or be hacked
[publisher_rpc]
#
@ -887,9 +899,6 @@
# value)
#metering_topic=metering
# Secret value for signing metering messages (string value)
#metering_secret=change this or be hacked
[rpc_notifier2]

View File

@ -29,6 +29,7 @@ import sys
from oslo.config import cfg
from ceilometer.publisher import rpc
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer import storage
from ceilometer.openstack.common import timeutils
@ -131,9 +132,9 @@ def main():
resource_metadata={},
source='artificial',
)
data = rpc.meter_message_from_counter(
data = utils.meter_message_from_counter(
c,
cfg.CONF.publisher_rpc.metering_secret)
cfg.CONF.publisher.metering_secret)
conn.record_metering_data(data)
n += 1
timestamp = timestamp + increment