Skip to content

Commit

Permalink
Merge 96dfaa6 into 5f5c11b
Browse files Browse the repository at this point in the history
  • Loading branch information
mkurek committed Oct 21, 2014
2 parents 5f5c11b + 96dfaa6 commit f65d7ad
Show file tree
Hide file tree
Showing 9 changed files with 558 additions and 7 deletions.
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
'python-novaclient==2.17.0',
'django-simple-history',
'djangorestframework==2.4.3',
'django-filter>=0.8',
],
entry_points={
'django.pluggable_app': [
Expand Down
23 changes: 22 additions & 1 deletion src/ralph_scrooge/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
ReST API for Scrooge
------------------------------------
Done with TastyPie.
Done with TastyPie and Django Rest Framework.
Scrooge API provide endpoint for services to push usages of their resources
by services / pricing objects.
Expand All @@ -19,6 +19,9 @@
import logging
from collections import defaultdict

from rest_framework import filters
from rest_framework.viewsets import ModelViewSet
from rest_framework.serializers import ModelSerializer
from tastypie import http, fields
from tastypie.authentication import ApiKeyAuthentication
from tastypie.resources import Resource
Expand All @@ -29,6 +32,7 @@
PricingObject,
PricingService,
ServiceEnvironment,
SyncStatus,
UsageType,
)

Expand Down Expand Up @@ -476,3 +480,20 @@ def _get_pricing_service_usages(cls, pricing_service_symbol, date):
usages.usages = [UsageObject(k, v) for k, v in u]
ps.usages.append(usages)
return ps


# =============================================================================
# SYNC STATUS API
# =============================================================================
class SyncStatusSerializer(ModelSerializer):
class Meta:
model = SyncStatus
exclude = ('created', 'modified', 'id', 'cache_version')


class SyncStatusViewSet(ModelViewSet):
queryset = SyncStatus.objects.all()
serializer_class = SyncStatusSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_fields = ('date', 'plugin', 'success')
resource_name = 'sync_status'
23 changes: 21 additions & 2 deletions src/ralph_scrooge/management/commands/scrooge_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@

from django.core.management.base import BaseCommand
from django.conf import settings

from ralph.util import plugin

from ralph_scrooge.models import SyncStatus


logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -45,6 +46,11 @@ def get_collect_plugins_names():

def _run_plugin(name, today):
logger.info('Running {0}...'.format(name))
success, message = False, None
try:
sync_status = SyncStatus.objects.get(plugin=name, date=today)
except SyncStatus.DoesNotExist:
sync_status = SyncStatus(plugin=name, date=today)
try:
success, message = plugin.run(
'scrooge',
Expand All @@ -57,7 +63,10 @@ def _run_plugin(name, today):
logger.exception("{0}: {1}".format(name, e))
raise
finally:
logger.info('{0}: Done'.format(message))
sync_status.success = success
sync_status.remarks = message
sync_status.save()
logger.info('Done: {0}'.format(message))


def run_plugins(today, plugins, run_only=False):
Expand Down Expand Up @@ -87,6 +96,16 @@ def run_plugins(today, plugins, run_only=False):
except Exception:
yield name, False

# save not executed plugins
for p in set(plugins) - tried:
status = SyncStatus.objects.get_or_create(
date=today,
plugin=p,
)[0]
status.success = False
status.remarks = 'Not executed'
status.save()


class Command(BaseCommand):
"""Retrieve data for pricing for today"""
Expand Down

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions src/ralph_scrooge/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
Statement,
)

from ralph_scrooge.models.sync import (
SyncStatus,
)

from ralph_scrooge.models.team import (
Team,
TeamBillingType,
Expand Down Expand Up @@ -94,6 +98,7 @@
'ServiceOwnership',
'ServiceUsageTypes',
'Statement',
'SyncStatus',
'Team',
'TeamBillingType',
'TeamCost',
Expand Down
42 changes: 42 additions & 0 deletions src/ralph_scrooge/models/sync.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

from django.db import models as db
from django.utils.translation import ugettext_lazy as _
from lck.django.common.models import TimeTrackable


class SyncStatus(TimeTrackable):
date = db.DateField()
plugin = db.CharField(
null=False,
blank=False,
max_length=100,
verbose_name=_("plugin name"),
)
success = db.BooleanField(
verbose_name=_("status"),
default=False,
)
remarks = db.TextField(
verbose_name=_("remarks"),
blank=True,
null=True,
)

class Meta:
verbose_name = _("sync status")
verbose_name_plural = _("sync statuses")
unique_together = ('date', 'plugin')
app_label = 'ralph_scrooge'

def __unicode__(self):
return '{}/{} : {}'.format(
self.date,
self.plugin,
_('Success') if self.success else _('Failed'),
)
2 changes: 1 addition & 1 deletion src/ralph_scrooge/plugins/collect/asset_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def update_asset_model(data):
"""
model, created = PricingObjectModel.objects.get_or_create(
model_id=data['model_id'],
type=PRICING_OBJECT_TYPES.ASSET,
type_id=PRICING_OBJECT_TYPES.ASSET,
)
model.name = data['name']
model.manufacturer = data['manufacturer']
Expand Down
8 changes: 6 additions & 2 deletions src/ralph_scrooge/tests/test_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from django.test import TestCase
from django.views.generic import View
from pluggableapp import PluggableApp
from rest_framework.viewsets import ViewSetMixin

from ralph.account.models import Perm
from ralph.ui.tests.functional.tests_view import LoginRedirectTest
Expand All @@ -28,8 +29,11 @@ def test_urls(self):
Checks if every view from urls is subclass of Base view
"""
for i in urls.__dict__.values():
if (inspect.isclass(i) and issubclass(i, View)
and not issubclass(i, BootstrapAngular)):
if (
inspect.isclass(i) and
issubclass(i, View) and
not issubclass(i, (BootstrapAngular, ViewSetMixin))
):
self.assertTrue(issubclass(i, Base))


Expand Down
8 changes: 7 additions & 1 deletion src/ralph_scrooge/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@

from django.conf.urls.defaults import include, patterns, url
from django.contrib.auth.decorators import login_required
from rest_framework import routers
from tastypie.api import Api

from ralph_scrooge.api import PricingServiceUsageResource
from ralph_scrooge.api import PricingServiceUsageResource, SyncStatusViewSet
from ralph_scrooge.views.bootstrapangular import BootstrapAngular
from ralph_scrooge.views.collect_plugins import CollectPlugins
from ralph_scrooge.views.extra_costs import ExtraCosts
Expand All @@ -36,6 +37,10 @@
for r in (PricingServiceUsageResource, ):
v09_api.register(r())

v09_router = routers.DefaultRouter()
for r in (SyncStatusViewSet, ):
v09_router.register(r.resource_name, r)

urlpatterns = patterns(
'',
url(
Expand All @@ -53,6 +58,7 @@
url(r'^rest/', include('ralph_scrooge.rest.urls')),
url(r'^leftmenu/(?P<menu_type>\S+)/$', login_required(left_menu)),
url(r'^api/', include(v09_api.urls)),
url(r'^api/', include(v09_router.urls)),
url(
r'^$',
login_required(BootstrapAngular.as_view()),
Expand Down

0 comments on commit f65d7ad

Please sign in to comment.