Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion django-cloudlaunch/baselaunch/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,15 @@ class OSCredsInline(admin.StackedInline):
extra = 1


class AzureCredsInline(admin.StackedInline):
model = models.AzureCredentials
form = forms.AzureCredentialsForm
formset = forms.DefaultRequiredInlineFormSet
extra = 1


class UserProfileAdmin(admin.ModelAdmin):
inlines = [AWSCredsInline, OSCredsInline]
inlines = [AWSCredsInline, OSCredsInline, AzureCredsInline]


class AppDeploymentsAdmin(admin.ModelAdmin):
Expand Down Expand Up @@ -109,6 +116,7 @@ class PublicServicesAdmin(admin.ModelAdmin):
admin.site.register(models.AWS, CloudAdmin)
admin.site.register(models.EC2, EC2Admin)
admin.site.register(models.S3, S3Admin)
admin.site.register(models.Azure, CloudAdmin)
admin.site.register(models.OpenStack, CloudAdmin)
admin.site.register(models.UserProfile, UserProfileAdmin)
admin.site.register(models.Usage, UsageAdmin)
Expand Down
11 changes: 11 additions & 0 deletions django-cloudlaunch/baselaunch/backend_plugins/cloudman_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,17 @@ def process_app_config(name, cloud_version_config, credentials, app_config):
ec2_creds = provider.security.get_or_create_ec2_credentials()
user_data['access_key'] = ec2_creds.access
user_data['secret_key'] = ec2_creds.secret

if hasattr(cloud, 'azure'):
user_data['cloud_type'] = 'azure'
user_data['region_name'] = cloud.azure.region_name
user_data['resource_group'] = cloud.azure.resource_group
user_data['storage_account'] = cloud.azure.storage_account
user_data['vm_default_user_name'] = cloud.azure.vm_default_user_name
user_data['subscription_id'] = credentials.get('azure_subscription_id')
user_data['client_id'] = credentials.get('azure_client_id')
user_data['secret'] = credentials.get('azure_secret')
user_data['tenant'] = credentials.get('azure_tenant')
else:
raise ValidationError({ "error":
"This version of CloudMan supports only EC2-compatible clouds."})
Expand Down
10 changes: 10 additions & 0 deletions django-cloudlaunch/baselaunch/domain_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,15 @@ def get_cloud_provider(cloud, cred_dict):
config.update(cred_dict)
return CloudProviderFactory().create_provider(ProviderList.AWS,
config)
elif isinstance(cloud, models.Azure):
config = {
'azure_region_name': cloud.region_name,
'azure_resource_group': cloud.resource_group,
'azure_storage_account':cloud.storage_account,
'azure_vm_default_user_name': cloud.vm_default_user_name
}
config.update(cred_dict)
return CloudProviderFactory().create_provider(ProviderList.AZURE,
config)
else:
raise Exception("Unrecognised cloud provider: %s" % cloud)
16 changes: 16 additions & 0 deletions django-cloudlaunch/baselaunch/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,22 @@ class Meta:
fields = '__all__'


class AzureCredentialsForm(ModelForm):

def __init__(self, *args, **kwargs):
super(AzureCredentialsForm, self).__init__(*args, **kwargs)
# restrict choices to Azure clouds only
self.fields['cloud'].queryset = models.Azure \
.objects.all()

secret = forms.CharField(widget=PasswordInput(render_value=True),
required=False)

class Meta:
model = models.AzureCredentials
fields = '__all__'


class DefaultRequiredInlineFormSet(BaseInlineFormSet):

def clean(self):
Expand Down
53 changes: 53 additions & 0 deletions django-cloudlaunch/baselaunch/migrations/0019_azure_credentials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@

# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-01-20 18:16
from __future__ import unicode_literals

import django
import fernet_fields

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('baselaunch', '0018_auto_20170613_1553'),
]

operations = [
migrations.CreateModel(
name='AZURE',
fields=[
('cloud_ptr',
models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True,
primary_key=True, serialize=False, to='baselaunch.Cloud')),
('region_name', models.CharField(max_length=100)),
('resource_group', models.CharField(max_length=100)),
('storage_account', models.CharField(max_length=100)),
('vm_default_user_name', models.CharField(max_length=100)),
],
options={
'verbose_name': 'Azure',
'verbose_name_plural': 'Azure',
},
bases=('baselaunch.cloud',),
),
migrations.CreateModel(
name='AzureCredentials',
fields=[
('credentials_ptr',
models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True,
primary_key=True, serialize=False, to='baselaunch.Credentials')),
('subscription_id', models.CharField(max_length=50)),
('client_id', models.CharField(blank=True, max_length=50, null=True)),
('secret', fernet_fields.fields.EncryptedCharField(blank=True, max_length=50, null=True)),
('tenant', models.CharField(blank=True, max_length=50, null=True))
],
options={
'verbose_name': 'Azure Credentials',
'verbose_name_plural': 'Azure Credentials',
},
bases=('baselaunch.credentials',),
)
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-01-20 18:16
from __future__ import unicode_literals

import django
import fernet_fields

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('baselaunch', '0019_azure_credentials'),
]

operations = [
migrations.DeleteModel('AZURE'),
migrations.CreateModel(
name='Azure',
fields=[
('cloud_ptr',
models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True,
primary_key=True, serialize=False, to='baselaunch.Cloud')),
('region_name', models.CharField(max_length=100)),
('resource_group', models.CharField(max_length=100)),
('storage_account', models.CharField(max_length=100)),
('vm_default_user_name', models.CharField(max_length=100)),
],
options={
'verbose_name': 'Azure',
'verbose_name_plural': 'Azure',
},
bases=('baselaunch.cloud',),
)
]
32 changes: 32 additions & 0 deletions django-cloudlaunch/baselaunch/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ class Meta:
verbose_name_plural = "OpenStack"


class Azure(Cloud):
resource_group = models.CharField(max_length=100, blank=True, null=False)
region_name = models.CharField(max_length=100, blank=True, null=False)
storage_account = models.CharField(max_length=100, blank=True, null=False)
vm_default_user_name = models.CharField(max_length=100, blank=True, null=False)


class Meta:
verbose_name = "Azure"
verbose_name_plural = "Azure"


class Image(DateNameAwareModel):
"""
A base Image model used by a virtual appliance.
Expand Down Expand Up @@ -302,6 +314,26 @@ def as_dict(self):
return d


class AzureCredentials(Credentials):
subscription_id = models.CharField(max_length=50, blank=False, null=False)
client_id = models.CharField(max_length=50, blank=False, null=False)
secret = EncryptedCharField(max_length=50, blank=False, null=False)
tenant = models.CharField(max_length=50, blank=True, null=True)

class Meta:
verbose_name = "Azure Credentials"
verbose_name_plural = "Azure Credentials"

def as_dict(self):
d = {
'azure_subscription_id': self.subscription_id,
'azure_client_id': self.client_id,
'azure_secret': self.secret,
'azure_tenant': self.tenant
}
return d


class UserProfile(models.Model):
# Link UserProfile to a User model instance
user = models.OneToOneField(User)
Expand Down
45 changes: 44 additions & 1 deletion django-cloudlaunch/baselaunch/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,8 @@ def get_region_name(self, obj):
return obj.aws.compute.ec2_region_name
elif hasattr(obj, 'openstack'):
return obj.openstack.region_name
elif hasattr(obj, 'azure'):
return obj.azure.region_name
else:
return "Cloud provider not recognized"

Expand All @@ -517,6 +519,8 @@ def get_cloud_type(self, obj):
return 'aws';
elif hasattr(obj, 'openstack'):
return 'openstack';
elif hasattr(obj, 'azure'):
return 'azure';
else:
return 'unknown';

Expand Down Expand Up @@ -545,6 +549,14 @@ def get_extra_data(self, obj):
'region_name': os.region_name,
'identity_api_version': os.identity_api_version
}
elif hasattr(obj, 'azure'):
azure = obj.azure
return {
'region_name': azure.region_name,
'resource_group': azure.resource_group,
'storage_account': azure.storage_account,
'vm_default_user_name': azure.vm_default_user_name
}
else:
return {}

Expand Down Expand Up @@ -740,6 +752,8 @@ class CredentialsSerializer(serializers.Serializer):
aws = CustomHyperlinkedIdentityField(view_name='awscredentials-list')
openstack = CustomHyperlinkedIdentityField(
view_name='openstackcredentials-list')
azure = CustomHyperlinkedIdentityField(
view_name='azurecredentials-list')


class AWSCredsSerializer(serializers.HyperlinkedModelSerializer):
Expand Down Expand Up @@ -772,9 +786,25 @@ class Meta:
exclude = ('password', 'user_profile')


class AzureCredsSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.IntegerField(read_only=True)
secret = serializers.CharField(
style={'input_type': 'password'},
write_only=True,
required=False
)
cloud_id = serializers.CharField(write_only=True)
cloud = CloudSerializer(read_only=True)

class Meta:
model = models.AzureCredentials
exclude = ('secret', 'user_profile')


class CloudConnectionAuthSerializer(serializers.Serializer):
aws_creds = AWSCredsSerializer(write_only=True, required=False)
openstack_creds = OpenstackCredsSerializer(write_only=True, required=False)
azure_creds = AzureCredsSerializer(write_only=True, required=False)
result = serializers.CharField(read_only=True)
details = serializers.CharField(read_only=True)

Expand All @@ -793,6 +823,7 @@ class UserSerializer(UserDetailsSerializer):
lookup_field=None)
aws_creds = serializers.SerializerMethodField()
openstack_creds = serializers.SerializerMethodField()
azure_creds = serializers.SerializerMethodField()

def get_aws_creds(self, obj):
"""
Expand All @@ -818,9 +849,21 @@ def get_openstack_creds(self, obj):
except models.UserProfile.DoesNotExist:
return ""

def get_azure_creds(self, obj):
"""
Include a URL for listing this bucket's contents
"""
try:
creds = obj.userprofile.credentials.filter(
azurecredentials__isnull=False).select_subclasses()
return AzureCredsSerializer(instance=creds, many=True,
context=self.context).data
except models.UserProfile.DoesNotExist:
return ""

class Meta(UserDetailsSerializer.Meta):
fields = UserDetailsSerializer.Meta.fields + \
('aws_creds', 'openstack_creds', 'credentials')
('aws_creds', 'openstack_creds', 'azure_creds', 'credentials')


### Public Services Serializers ###
Expand Down
2 changes: 2 additions & 0 deletions django-cloudlaunch/baselaunch/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@
profile_router.register(r'credentials/aws', views.AWSCredentialsViewSet)
profile_router.register(r'credentials/openstack',
views.OpenstackCredentialsViewSet)
profile_router.register(r'credentials/azure',
views.AzureCredentialsViewSet)

infrastructure_regex_pattern = r'api/v1/infrastructure/'
auth_regex_pattern = r'api/v1/auth/'
Expand Down
14 changes: 14 additions & 0 deletions django-cloudlaunch/baselaunch/view_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@ def get_credentials_from_request(cloud, request):
}
else:
return {}
elif isinstance(cloud, models.Azure):
azure_subscription_id = request.META.get('HTTP_CL_AZURE_SUBSCRIPTION_ID')
azure_client_id = request.META.get('HTTP_CL_AZURE_CLIENT_ID')
azure_secret = request.META.get('HTTP_CL_AZURE_SECRET')
azure_tenant = request.META.get('HTTP_CL_AZURE_TENANT')

if azure_subscription_id and azure_client_id and azure_secret and azure_tenant:
return {'azure_subscription_id': azure_subscription_id,
'azure_client_id': azure_client_id,
'azure_secret': azure_secret,
'azure_tenant': azure_tenant
}
else:
return {}
else:
raise Exception("Unrecognised cloud provider: %s" % cloud)

Expand Down
15 changes: 15 additions & 0 deletions django-cloudlaunch/baselaunch/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,21 @@ def get_queryset(self):
openstackcredentials__isnull=False).select_subclasses()
return models.OpenStackCredentials.objects.none()

class AzureCredentialsViewSet(CredentialsViewSet):
"""
API endpoint that allows Azure credentials to be viewed or edited.
"""
queryset = models.AzureCredentials.objects.all()
serializer_class = serializers.AzureCredsSerializer
#permission_classes = [permissions.DjangoModelPermissions]

def get_queryset(self):
user = self.request.user
if hasattr(user, 'userprofile'):
return user.userprofile.credentials.filter(
azurecredentials__isnull=False).select_subclasses()
return models.AzureCredentials.objects.none()


class DeploymentViewSet(viewsets.ModelViewSet):
"""
Expand Down
9 changes: 9 additions & 0 deletions django-cloudlaunch/cloudlaunch/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@
'cl-os-identity-api-version',
'cl-aws-access-key',
'cl-aws-secret-key',
'cl-azure-region-name',
'cl-azure-resource_group',
'cl-azure-subscription-id'
'cl-azure-client-id',
'cl-azure-secret',
'cl-azure-tenant',
'cl-storage-account',
'cl-azure-vm-default-user-name'

)
# End: django-cors-headers settings

Expand Down