diff --git a/django-cloudlaunch/cloudlaunch/migrations/0003_deployment_credentials_relationship.py b/django-cloudlaunch/cloudlaunch/migrations/0003_deployment_credentials_relationship.py new file mode 100644 index 00000000..133bd9ab --- /dev/null +++ b/django-cloudlaunch/cloudlaunch/migrations/0003_deployment_credentials_relationship.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-12-14 12:26 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('cloudlaunch', '0002_application_display_order'), + ] + + operations = [ + migrations.AlterModelOptions( + name='application', + options={}, + ), + migrations.AddField( + model_name='applicationdeployment', + name='credentials', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='deployment_creds', to='djcloudbridge.Credentials'), + ), + migrations.AlterField( + model_name='application', + name='category', + field=models.ManyToManyField(blank=True, to='cloudlaunch.AppCategory'), + ), + ] diff --git a/django-cloudlaunch/cloudlaunch/models.py b/django-cloudlaunch/cloudlaunch/models.py index 8834fb30..dd7d8a84 100644 --- a/django-cloudlaunch/cloudlaunch/models.py +++ b/django-cloudlaunch/cloudlaunch/models.py @@ -25,7 +25,7 @@ class Image(cb_models.DateNameAwareModel): class CloudImage(Image): - cloud = models.ForeignKey('djcloudbridge.Cloud', blank=True, null=True) + cloud = models.ForeignKey(cb_models.Cloud, blank=True, null=True) def __str__(self): return "{0} (on {1})".format(self.name, self.cloud.name) @@ -68,7 +68,7 @@ class Application(cb_models.DateNameAwareModel): slug = models.SlugField(max_length=100, primary_key=True) status = models.CharField(max_length=50, blank=True, null=True, choices=STATUS_CHOICES, default=DEV) - category = models.ManyToManyField(AppCategory, blank=True, null=True) + category = models.ManyToManyField(AppCategory, blank=True) # summary is the size of a tweet. description can be of arbitrary length summary = models.CharField(max_length=140, blank=True, null=True) maintainer = models.CharField(max_length=255, blank=True, null=True) @@ -101,9 +101,6 @@ def save(self, *args, **kwargs): super(Application, self).save(*args, **kwargs) - class Meta: - ordering = ['name'] - class ApplicationVersion(models.Model): application = models.ForeignKey(Application, related_name="versions") @@ -115,7 +112,7 @@ class ApplicationVersion(models.Model): default_launch_config = models.TextField(max_length=1024 * 16, help_text="Version " "specific configuration data to parameterize the launch with.", blank=True, null=True) - default_cloud = models.ForeignKey('djcloudbridge.Cloud', related_name='+', blank=True, null=True, + default_cloud = models.ForeignKey(cb_models.Cloud, related_name='+', blank=True, null=True, on_delete=models.SET_NULL) def save(self, *args, **kwargs): @@ -139,7 +136,7 @@ class Meta: class ApplicationVersionCloudConfig(models.Model): application_version = models.ForeignKey(ApplicationVersion, related_name="app_version_config") - cloud = models.ForeignKey('djcloudbridge.Cloud', related_name="app_version_config") + cloud = models.ForeignKey(cb_models.Cloud, related_name="app_version_config") image = ChainedForeignKey(CloudImage, chained_field="cloud", chained_model_field="cloud") default_instance_type = models.CharField(max_length=256, blank=True, null=True) # Userdata max length is 16KB @@ -172,13 +169,14 @@ class ApplicationDeployment(cb_models.DateNameAwareModel): owner = models.ForeignKey(User, null=False) archived = models.BooleanField(blank=True, default=False) application_version = models.ForeignKey(ApplicationVersion, null=False) - target_cloud = models.ForeignKey('djcloudbridge.Cloud', null=False) + target_cloud = models.ForeignKey(cb_models.Cloud, null=False) provider_settings = models.TextField( max_length=1024 * 16, help_text="Cloud provider specific settings " "used for this launch.", blank=True, null=True) application_config = models.TextField( max_length=1024 * 16, help_text="Application configuration data used " "for this launch.", blank=True, null=True) + credentials = models.ForeignKey(cb_models.Credentials, related_name="deployment_creds", null=True) class ApplicationDeploymentTask(models.Model): diff --git a/django-cloudlaunch/cloudlaunch/serializers.py b/django-cloudlaunch/cloudlaunch/serializers.py index 5a1b96c5..abc80a5f 100644 --- a/django-cloudlaunch/cloudlaunch/serializers.py +++ b/django-cloudlaunch/cloudlaunch/serializers.py @@ -9,6 +9,7 @@ from . import tasks from . import util +from djcloudbridge import models as cb_models from djcloudbridge import serializers as cb_serializers from djcloudbridge import view_helpers from djcloudbridge.drf_helpers import CustomHyperlinkedIdentityField @@ -147,16 +148,19 @@ def create(self, validated_data): request = self.context.get('view').request dpk = self.context['view'].kwargs.get('deployment_pk') dpl = models.ApplicationDeployment.objects.get(id=dpk) - credentials = view_helpers.get_credentials(dpl.target_cloud, request) + creds = (cb_models.Credentials.objects.get_subclass( + id=dpl.credentials.id).as_dict() + if dpl.credentials + else view_helpers.get_credentials(dpl.target_cloud, request)) try: if action == models.ApplicationDeploymentTask.HEALTH_CHECK: - async_result = tasks.health_check.delay(dpl.pk, credentials) + async_result = tasks.health_check.delay(dpl.pk, creds) elif action == models.ApplicationDeploymentTask.RESTART: async_result = tasks.manage_appliance.delay('restart', dpl.pk, - credentials) + creds) elif action == models.ApplicationDeploymentTask.DELETE: async_result = tasks.manage_appliance.delay('delete', dpl.pk, - credentials) + creds) return models.ApplicationDeploymentTask.objects.create( action=action, deployment=dpl, celery_id=async_result.task_id) except serializers.ValidationError as ve: @@ -190,12 +194,13 @@ class DeploymentSerializer(serializers.ModelSerializer): tasks = CustomHyperlinkedIdentityField(view_name='deployment_task-list', lookup_field='id', lookup_url_kwarg='deployment_pk') + credentials = serializers.PrimaryKeyRelatedField(read_only=True) class Meta: model = models.ApplicationDeployment fields = ('id','name', 'application', 'application_version', 'target_cloud', 'provider_settings', 'application_config', 'added', 'updated', 'owner', 'config_app', 'app_version_details', - 'tasks', 'latest_task', 'launch_task', 'archived') + 'tasks', 'latest_task', 'launch_task', 'archived', 'credentials') def get_latest_task(self, obj): """Provide task info about the most recenly updated deployment task.""" @@ -258,6 +263,7 @@ def create(self, validated_data): del validated_data['config_app'] validated_data['owner_id'] = request.user.id validated_data['application_config'] = json.dumps(merged_config) + validated_data['credentials_id'] = credentials.get('id') or None app_deployment = super(DeploymentSerializer, self).create(validated_data) self.log_usage(cloud_version_config, app_deployment, sanitised_app_config, request.user) models.ApplicationDeploymentTask.objects.create(