Skip to content

Commit

Permalink
Merge pull request #50 from octue/updates-pre-unfold
Browse files Browse the repository at this point in the history
Updates pre unfold
  • Loading branch information
thclark authored Nov 17, 2023
2 parents 8ee28bf + cf2d9a8 commit 9883a6e
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 27 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "django-gcp"
version = "0.10.5"
version = "0.10.6"
description = "Utilities to run Django on Google Cloud Platform"
authors = ["Tom Clark"]
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion terraform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ It's already proven invaluable for testing and development of the tasks module.
We're currently learning terraform and expanding our DevOps expertise, so expect our workflows
to change dramatically in this area.

In the meaantime, used with a different project ID, performing a `terraform apply`
In the meantime, used with a different project ID, performing a `terraform apply`
on a fresh GCP project with this configuration (supply the project ID as a variable) should
give you the resources required to run the management tasks to demonstrate the example test
server (you'll need to manage service accounts yourself at the time of writing).
Expand Down
62 changes: 41 additions & 21 deletions terraform/iam.tf
Original file line number Diff line number Diff line change
@@ -1,31 +1,51 @@
# You need to start with a service account called "terraform" which has both the 'editor' and 'owner' basic permissions.
# This allows it to assign permissions to resources per https://cloud.google.com/iam/docs/understanding-roles
#
# Start by assigning the permissions that it needs itself

# Allows django-gcp.tasks to create periodic tasks for you using google cloud scheduler
# resource "google_project_iam_binding" "terraform_serviceaccount_bindings" {
# count = length(var.terraform_serviceaccount_roles)
# project = var.project
# role = var.terraform_serviceaccount_roles[count.index]
# members = [
# "serviceAccount:terraform@octue-django-gcp.iam.gserviceaccount.com",
# ]
# }


resource "google_service_account" "dev_thclark" {
account_id = "dev-thclark"
display_name = "dev-thclark"
project = "octue-django-gcp"
project = var.project
}


resource "google_service_account" "dev_lukasvinclav" {
account_id = "dev-lukasvinclav"
display_name = "dev-lukasvinclav"
project = var.project
}


# For iam bindings to storage buckets see terraform/storage.tf


resource "google_project_iam_binding" "errorreporting_writer" {
project = var.project
role = "roles/errorreporting.writer"
members = [
"serviceAccount:${google_service_account.dev_thclark.email}",
"serviceAccount:${google_service_account.dev_lukasvinclav.email}",
]
}


# Allows django-gcp.tasks to create periodic tasks for you using google cloud scheduler
# resource "google_project_iam_binding" "cloudscheduler_jobs_update" {
# project = var.project
# role = "roles/CloudSchedulerAdmin"
# Allow django-gcp.tasks to create and update task queues
resource "google_project_iam_binding" "cloudtasks_admin" {
project = var.project
role = "roles/cloudtasks.admin"
members = [
"serviceAccount:${google_service_account.dev_thclark.email}",
"serviceAccount:${google_service_account.dev_lukasvinclav.email}",
]
}


# members = [
# "serviceAccount:${google_service_account.dev_thclark.email}",
# ]
# }
# Allow django-gcp.tasks to create periodic tasks in google cloud scheduler
resource "google_project_iam_binding" "cloudscheduler_admin" {
project = var.project
role = "roles/cloudscheduler.admin"
members = [
"serviceAccount:${google_service_account.dev_thclark.email}",
"serviceAccount:${google_service_account.dev_lukasvinclav.email}",
]
}
18 changes: 16 additions & 2 deletions terraform/storage.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ resource "google_storage_bucket_iam_binding" "static_assets_object_viewer" {
]
}


# Allow developers to run collectstatic
resource "google_storage_bucket_iam_binding" "static_assets_object_admin" {
bucket = google_storage_bucket.static_assets.name
role = "roles/storage.objectAdmin"
members = [
"serviceAccount:${google_service_account.dev_thclark.email}",
"serviceAccount:${google_service_account.dev_lukasvinclav.email}"
]
}


# Add a media bucket (private contents)
# Note: CORS are set to allow direct uploads, enabling upload of files
# larger than 32 mb (Cloud Run has a hard limit on file upload size)
Expand All @@ -47,7 +59,8 @@ resource "google_storage_bucket_iam_binding" "media_assets_object_admin" {
bucket = google_storage_bucket.media_assets.name
role = "roles/storage.objectAdmin"
members = [
"serviceAccount:${google_service_account.dev_thclark.email}"
"serviceAccount:${google_service_account.dev_thclark.email}",
"serviceAccount:${google_service_account.dev_lukasvinclav.email}"
]
}

Expand Down Expand Up @@ -78,6 +91,7 @@ resource "google_storage_bucket_iam_binding" "extra_versioned_assets_object_admi
bucket = google_storage_bucket.extra_versioned_assets.name
role = "roles/storage.objectAdmin"
members = [
"serviceAccount:${google_service_account.dev_thclark.email}"
"serviceAccount:${google_service_account.dev_thclark.email}",
"serviceAccount:${google_service_account.dev_lukasvinclav.email}"
]
}
6 changes: 6 additions & 0 deletions tests/server/example/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from tests.server.example.models import (
ExampleBlankBlobFieldModel,
ExampleBlobFieldModel,
ExampleMultipleBlobFieldModel,
ExampleStorageModel,
ExampleUneditableBlobFieldModel,
)
Expand All @@ -24,7 +25,12 @@ class ExampleUneditableBlobFieldModelAdmin(admin.ModelAdmin):
"""A basic admin panel to demonstrate the direct upload storage behaviour where blank=True"""


class ExampleMultipleBlobFieldModelAdmin(admin.ModelAdmin):
"""A basic admin panel to demonstrate the direct upload storage behaviour where multiple blobfields are used"""


admin.site.register(ExampleStorageModel, ExampleStorageModelAdmin)
admin.site.register(ExampleBlobFieldModel, ExampleBlobFieldModelAdmin)
admin.site.register(ExampleBlankBlobFieldModel, ExampleBlankBlobFieldModelAdmin)
admin.site.register(ExampleUneditableBlobFieldModel, ExampleUneditableBlobFieldModelAdmin)
admin.site.register(ExampleMultipleBlobFieldModel, ExampleMultipleBlobFieldModelAdmin)
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Generated by Django 4.1.7 on 2023-11-17 15:19

import django_gcp.storage.fields
from django.db import migrations, models

import tests.server.example.models


class Migration(migrations.Migration):

dependencies = [
("example", "0005_examplecallbackblobfieldmodel_and_more"),
]

operations = [
migrations.CreateModel(
name="ExampleMultipleBlobFieldModel",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("category", models.CharField(blank=True, max_length=20, null=True)),
(
"blob1",
django_gcp.storage.fields.BlobField(
accept_mimetype="*/*",
default=None,
get_destination_path=tests.server.example.models.get_destination_path,
help_text="GCP cloud storage object",
ingress_to="_tmp/",
on_change=None,
overwrite_mode="never",
store_key="media",
),
),
(
"blob2",
django_gcp.storage.fields.BlobField(
accept_mimetype="*/*",
default=None,
get_destination_path=tests.server.example.models.get_destination_path,
help_text="GCP cloud storage object",
ingress_to="_tmp/",
on_change=None,
overwrite_mode="never",
store_key="media",
),
),
(
"blob3",
django_gcp.storage.fields.BlobField(
accept_mimetype="*/*",
default=None,
get_destination_path=tests.server.example.models.get_destination_path,
help_text="GCP cloud storage object",
ingress_to="_tmp/",
on_change=None,
overwrite_mode="never",
store_key="media",
),
),
],
),
]
31 changes: 29 additions & 2 deletions tests/server/example/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from uuid import uuid4
from django.db.models import CharField, FileField, Model
from django_gcp.storage.fields import BlobField

Expand Down Expand Up @@ -55,9 +56,14 @@ def get_destination_path(
"""
# Demonstrate using another field to name the object
category = f"{instance.category}/" if instance.category is not None else ""

# You may wish to add a timestamp, or random string to prevent collisions
# In this case we do the very simple thing of using the original name
return f"{category}{original_name}", allow_overwrite
# In this case we do the very simple thing of using the original name with random prefix
# If you attempt to overwrite while allow_ovewrite is false, a server error will raise.
# Only set allow_overwrite = True if you really, REALLY, know what you're doing!
random_prefix = str(uuid4())[0:8]

return f"{category}{random_prefix}-{original_name}", allow_overwrite


class ExampleStorageModel(Model):
Expand Down Expand Up @@ -137,6 +143,27 @@ class Meta:
app_label = "example"


class ExampleMultipleBlobFieldModel(Model):
"""
An example model containing multiple BlobFields
This model was started as a FileField model then migrated, so check the migrations
to see how that worked.
"""

# This charfield is added to demonstrate that other fields of the model can be used
# in order to set the blob name
category = CharField(max_length=20, blank=True, null=True)

blob1 = BlobField(get_destination_path=get_destination_path, store_key="media")
blob2 = BlobField(get_destination_path=get_destination_path, store_key="media")
blob3 = BlobField(get_destination_path=get_destination_path, store_key="media")

class Meta:
"""Metaclass defining this model to reside in the example app"""

app_label = "example"


def my_on_change_callback(value, instance):
"""Demonstrate the on_change callback functionality"""
if value is None:
Expand Down

0 comments on commit 9883a6e

Please sign in to comment.