diff --git a/nova/objects/__init__.py b/nova/objects/__init__.py index 5346ddf67099..77e62b6cf5e0 100644 --- a/nova/objects/__init__.py +++ b/nova/objects/__init__.py @@ -65,3 +65,4 @@ def register_all(): __import__('nova.objects.vcpu_model') __import__('nova.objects.virt_cpu_topology') __import__('nova.objects.virtual_interface') + __import__('nova.objects.volume_usage') diff --git a/nova/objects/volume_usage.py b/nova/objects/volume_usage.py new file mode 100644 index 000000000000..93b79759302f --- /dev/null +++ b/nova/objects/volume_usage.py @@ -0,0 +1,59 @@ +# 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. + +from nova import db +from nova.objects import base +from nova.objects import fields + + +@base.NovaObjectRegistry.register +class VolumeUsage(base.NovaPersistentObject, base.NovaObject): + # Version 1.0: Initial version + VERSION = '1.0' + + fields = { + 'id': fields.IntegerField(read_only=True), + 'volume_id': fields.UUIDField(), + 'instance_uuid': fields.UUIDField(nullable=True), + 'project_id': fields.StringField(nullable=True), + 'user_id': fields.StringField(nullable=True), + 'availability_zone': fields.StringField(nullable=True), + 'tot_last_refreshed': fields.DateTimeField(nullable=True, + read_only=True), + 'tot_reads': fields.IntegerField(read_only=True), + 'tot_read_bytes': fields.IntegerField(read_only=True), + 'tot_writes': fields.IntegerField(read_only=True), + 'tot_write_bytes': fields.IntegerField(read_only=True), + 'curr_last_refreshed': fields.DateTimeField(nullable=True, + read_only=True), + 'curr_reads': fields.IntegerField(), + 'curr_read_bytes': fields.IntegerField(), + 'curr_writes': fields.IntegerField(), + 'curr_write_bytes': fields.IntegerField() + } + + @staticmethod + def _from_db_object(context, vol_usage, db_vol_usage): + for field in vol_usage.fields: + setattr(vol_usage, field, db_vol_usage[field]) + vol_usage._context = context + vol_usage.obj_reset_changes() + return vol_usage + + @base.remotable + def save(self, update_totals=False): + db_vol_usage = db.vol_usage_update( + self._context, self.volume_id, self.curr_reads, + self.curr_read_bytes, self.curr_writes, self.curr_write_bytes, + self.instance_uuid, self.project_id, self.user_id, + self.availability_zone, update_totals=update_totals) + self._from_db_object(self._context, self, db_vol_usage) diff --git a/nova/tests/unit/objects/test_objects.py b/nova/tests/unit/objects/test_objects.py index 85faf140e95b..90dab530437a 100644 --- a/nova/tests/unit/objects/test_objects.py +++ b/nova/tests/unit/objects/test_objects.py @@ -1170,6 +1170,7 @@ object_data = { 'VirtCPUTopology': '1.0-fc694de72e20298f7c6bab1083fd4563', 'VirtualInterface': '1.0-19921e38cba320f355d56ecbf8f29587', 'VirtualInterfaceList': '1.0-9750e2074437b3077e46359102779fc6', + 'VolumeUsage': '1.0-6c8190c46ce1469bb3286a1f21c2e475', } diff --git a/nova/tests/unit/objects/test_volume_usage.py b/nova/tests/unit/objects/test_volume_usage.py new file mode 100644 index 000000000000..17188287fa74 --- /dev/null +++ b/nova/tests/unit/objects/test_volume_usage.py @@ -0,0 +1,89 @@ +# 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. + +import mock +from oslo_utils import timeutils + +from nova import objects +from nova.tests.unit.objects import test_objects + + +NOW = timeutils.utcnow().replace(microsecond=0) + +fake_vol_usage = { + 'created_at': NOW, + 'updated_at': None, + 'deleted_at': None, + 'deleted': 0, + 'id': 1, + 'volume_id': 'fake-vol-id', + 'instance_uuid': 'fake-inst-uuid', + 'project_id': 'fake-project-id', + 'user_id': 'fake-user-id', + 'availability_zone': None, + 'tot_last_refreshed': None, + 'tot_reads': 0, + 'tot_read_bytes': 0, + 'tot_writes': 0, + 'tot_write_bytes': 0, + 'curr_last_refreshed': NOW, + 'curr_reads': 10, + 'curr_read_bytes': 20, + 'curr_writes': 30, + 'curr_write_bytes': 40, + } + + +class _TestVolumeUsage(object): + @mock.patch('nova.db.vol_usage_update', return_value=fake_vol_usage) + def test_save(self, mock_upd): + vol_usage = objects.VolumeUsage(self.context) + vol_usage.volume_id = 'fake-vol-id' + vol_usage.instance_uuid = 'fake-inst-uuid' + vol_usage.project_id = 'fake-project-id' + vol_usage.user_id = 'fake-user-id' + vol_usage.availability_zone = None + vol_usage.curr_reads = 10 + vol_usage.curr_read_bytes = 20 + vol_usage.curr_writes = 30 + vol_usage.curr_write_bytes = 40 + vol_usage.save() + mock_upd.assert_called_once_with( + self.context, 'fake-vol-id', 10, 20, 30, 40, 'fake-inst-uuid', + 'fake-project-id', 'fake-user-id', None, update_totals=False) + self.compare_obj(vol_usage, fake_vol_usage) + + @mock.patch('nova.db.vol_usage_update', return_value=fake_vol_usage) + def test_save_update_totals(self, mock_upd): + vol_usage = objects.VolumeUsage(self.context) + vol_usage.volume_id = 'fake-vol-id' + vol_usage.instance_uuid = 'fake-inst-uuid' + vol_usage.project_id = 'fake-project-id' + vol_usage.user_id = 'fake-user-id' + vol_usage.availability_zone = None + vol_usage.curr_reads = 10 + vol_usage.curr_read_bytes = 20 + vol_usage.curr_writes = 30 + vol_usage.curr_write_bytes = 40 + vol_usage.save(update_totals=True) + mock_upd.assert_called_once_with( + self.context, 'fake-vol-id', 10, 20, 30, 40, 'fake-inst-uuid', + 'fake-project-id', 'fake-user-id', None, update_totals=True) + self.compare_obj(vol_usage, fake_vol_usage) + + +class TestVolumeUsage(test_objects._LocalTest, _TestVolumeUsage): + pass + + +class TestRemoteVolumeUsage(test_objects._RemoteTest, _TestVolumeUsage): + pass