pulumi-django-azure 1.0.2__py3-none-any.whl → 1.0.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pulumi-django-azure might be problematic. Click here for more details.

@@ -0,0 +1 @@
1
+ from .django_deployment import DjangoDeployment # noqa: F401
@@ -0,0 +1,561 @@
1
+ from typing import Optional, Sequence
2
+
3
+ import pulumi
4
+ import pulumi_azure_native as azure
5
+ import pulumi_random
6
+
7
+
8
+ class DjangoDeployment(pulumi.ComponentResource):
9
+ HEALTH_CHECK_PATH = "/health-check"
10
+
11
+ def __init__(
12
+ self,
13
+ name,
14
+ tenant_id: str,
15
+ resource_group_name: pulumi.Input[str],
16
+ vnet: azure.network.VirtualNetwork,
17
+ pgsql_ip_prefix: str,
18
+ appservice_ip_prefix: str,
19
+ app_service_sku: azure.web.SkuDescriptionArgs,
20
+ storage_account_name: str,
21
+ cdn_host: Optional[str],
22
+ opts=None,
23
+ ):
24
+ """
25
+ Create a Django deployment.
26
+
27
+ :param name: The name of the deployment, will be used to name subresources.
28
+ :param tenant_id: The Entra tenant ID for the database authentication.
29
+ :param resource_group_name: The resource group name to create the resources in.
30
+ :param vnet: The virtual network to create the subnets in.
31
+ :param pgsql_ip_prefix: The IP prefix for the PostgreSQL subnet.
32
+ :param appservice_ip_prefix: The IP prefix for the app service subnet.
33
+ :param app_service_sku: The SKU for the app service plan.
34
+ :param storage_account_name: The name of the storage account. Should be unique across Azure.
35
+ :param cdn_host: A custom CDN host name (optional)
36
+ :param opts: The resource options
37
+ """
38
+
39
+ super().__init__("pkg:index:DjangoDeployment", name, None, opts)
40
+
41
+ # child_opts = pulumi.ResourceOptions(parent=self)
42
+
43
+ self._name = name
44
+ self._tenant_id = tenant_id
45
+ self._rg = resource_group_name
46
+ self._vnet = vnet
47
+
48
+ # Storage resources
49
+ self._create_storage(account_name=storage_account_name)
50
+ self._cdn_host = self._create_cdn(custom_host=cdn_host)
51
+
52
+ # PostgreSQL resources
53
+ self._create_database(ip_prefix=pgsql_ip_prefix)
54
+
55
+ # Subnet for the apps
56
+ self._app_subnet = self._create_subnet(
57
+ name="app-service",
58
+ prefix=appservice_ip_prefix,
59
+ delegation_service="Microsoft.Web/serverFarms",
60
+ service_endpoints=["Microsoft.Storage"],
61
+ )
62
+
63
+ # Create App Service plan that will host all websites
64
+ self._app_service_plan = self._create_app_service_plan(sku=app_service_sku)
65
+
66
+ # Create a pgAdmin app
67
+ self._create_pgadmin_app()
68
+
69
+ def _create_storage(self, account_name: str):
70
+ # Create blob storage
71
+ self._storage_account = azure.storage.StorageAccount(
72
+ f"sa-{self._name}",
73
+ resource_group_name=self._rg,
74
+ account_name=account_name,
75
+ sku=azure.storage.SkuArgs(
76
+ name=azure.storage.SkuName.STANDARD_LRS,
77
+ ),
78
+ kind=azure.storage.Kind.STORAGE_V2,
79
+ access_tier=azure.storage.AccessTier.HOT,
80
+ allow_blob_public_access=True,
81
+ public_network_access=azure.storage.PublicNetworkAccess.ENABLED,
82
+ enable_https_traffic_only=True,
83
+ )
84
+
85
+ def _create_cdn(self, custom_host: Optional[str]) -> pulumi.Output[str]:
86
+ """
87
+ Create a CDN endpoint. If a host name is given, it will be used as the custom domain.
88
+ Otherwise, the default CDN host name will be returned.
89
+
90
+ :param custom_host: The custom domain (optional)
91
+ :return: The CDN host name
92
+ """
93
+
94
+ # Put CDN in front
95
+ cdn = azure.cdn.Profile(
96
+ f"cdn-{self._name}",
97
+ resource_group_name=self._rg,
98
+ location="global",
99
+ sku=azure.cdn.SkuArgs(
100
+ name=azure.cdn.SkuName.STANDARD_MICROSOFT,
101
+ ),
102
+ )
103
+
104
+ endpoint_origin = self._storage_account.primary_endpoints.apply(
105
+ lambda primary_endpoints: primary_endpoints.blob.replace("https://", "").replace("/", "")
106
+ )
107
+
108
+ self._cdn_endpoint = azure.cdn.Endpoint(
109
+ f"cdn-endpoint-{self._name}",
110
+ resource_group_name=self._rg,
111
+ location="global",
112
+ is_compression_enabled=True,
113
+ content_types_to_compress=[
114
+ "application/javascript",
115
+ "application/json",
116
+ "application/x-javascript",
117
+ "application/xml",
118
+ "text/css",
119
+ "text/html",
120
+ "text/javascript",
121
+ "text/plain",
122
+ ],
123
+ is_http_allowed=False,
124
+ is_https_allowed=True,
125
+ profile_name=cdn.name,
126
+ origin_host_header=endpoint_origin,
127
+ origins=[azure.cdn.DeepCreatedOriginArgs(name="origin-storage", host_name=endpoint_origin)],
128
+ query_string_caching_behavior=azure.cdn.QueryStringCachingBehavior.IGNORE_QUERY_STRING,
129
+ )
130
+
131
+ pulumi.export("cdn_cname", self._cdn_endpoint.host_name)
132
+
133
+ # Add custom domain if given
134
+ if custom_host:
135
+ azure.cdn.CustomDomain(
136
+ f"cdn-custom-domain-{self._name}",
137
+ resource_group_name=self._rg,
138
+ profile_name=cdn.name,
139
+ endpoint_name=self._cdn_endpoint.name,
140
+ host_name=custom_host,
141
+ )
142
+
143
+ return custom_host
144
+ else:
145
+ # Return the default CDN host name
146
+ return self._cdn_endpoint.host_name
147
+
148
+ def _create_database(self, ip_prefix: str):
149
+ # Create subnet for PostgreSQL
150
+ subnet = self._create_subnet(
151
+ name="pgsql",
152
+ prefix=ip_prefix,
153
+ delegation_service="Microsoft.DBforPostgreSQL/flexibleServers",
154
+ )
155
+
156
+ # Create private DNS zone
157
+ dns = azure.network.PrivateZone(
158
+ f"dns-pgsql-{self._name}",
159
+ resource_group_name=self._rg,
160
+ location="global",
161
+ # The zone name must end with this to work with Azure DB
162
+ private_zone_name=f"{self._name}.postgres.database.azure.com",
163
+ )
164
+
165
+ # Link the private DNS zone to the VNet in order to make resolving work
166
+ azure.network.VirtualNetworkLink(
167
+ f"vnet-link-pgsql-{self._name}",
168
+ resource_group_name=self._rg,
169
+ location="global",
170
+ private_zone_name=dns.name,
171
+ virtual_network=azure.network.SubResourceArgs(id=self._vnet.id),
172
+ registration_enabled=False,
173
+ )
174
+
175
+ # Create PostgreSQL server
176
+ self._pgsql = azure.dbforpostgresql.Server(
177
+ f"pgsql-{self._name}",
178
+ resource_group_name=self._rg,
179
+ sku=azure.dbforpostgresql.SkuArgs(
180
+ name="Standard_B2s",
181
+ tier=azure.dbforpostgresql.SkuTier.BURSTABLE,
182
+ ),
183
+ version="16",
184
+ auth_config=azure.dbforpostgresql.AuthConfigArgs(
185
+ password_auth=azure.dbforpostgresql.PasswordAuthEnum.DISABLED,
186
+ active_directory_auth=azure.dbforpostgresql.ActiveDirectoryAuthEnum.ENABLED,
187
+ tenant_id=self._tenant_id,
188
+ ),
189
+ storage=azure.dbforpostgresql.StorageArgs(storage_size_gb=32),
190
+ network=azure.dbforpostgresql.NetworkArgs(
191
+ delegated_subnet_resource_id=subnet.id,
192
+ private_dns_zone_arm_resource_id=dns.id,
193
+ ),
194
+ backup=azure.dbforpostgresql.BackupArgs(
195
+ backup_retention_days=7,
196
+ geo_redundant_backup=azure.dbforpostgresql.GeoRedundantBackupEnum.DISABLED,
197
+ ),
198
+ )
199
+
200
+ pulumi.export("pgsql_host", self._pgsql.fully_qualified_domain_name)
201
+
202
+ def _create_subnet(
203
+ self, name, prefix, delegation_service: Optional[str] = None, service_endpoints: Sequence[str] = []
204
+ ) -> azure.network.Subnet:
205
+ """
206
+ Generic method to create a subnet with a delegation.
207
+
208
+ :param name: The name of the subnet
209
+ :param prefix: The IP prefix
210
+ :param delegation_service: The service to delegate to
211
+ :param service_endpoints: The service endpoints to enable
212
+ :return: The subnet
213
+ """
214
+
215
+ if delegation_service:
216
+ delegation_service = azure.network.DelegationArgs(
217
+ name=f"delegation-{name}-{self._name}",
218
+ service_name=delegation_service,
219
+ )
220
+
221
+ service_endpoints = [azure.network.ServiceEndpointPropertiesFormatArgs(service=s) for s in service_endpoints]
222
+
223
+ return azure.network.Subnet(
224
+ f"subnet-{name}-{self._name}",
225
+ resource_group_name=self._rg,
226
+ virtual_network_name=self._vnet.name,
227
+ address_prefix=prefix,
228
+ delegations=[delegation_service],
229
+ service_endpoints=service_endpoints,
230
+ )
231
+
232
+ def _create_app_service_plan(self, sku: azure.web.SkuDescriptionArgs) -> azure.web.AppServicePlan:
233
+ # Create App Service plan
234
+ return azure.web.AppServicePlan(
235
+ f"asp-{self._name}",
236
+ resource_group_name=self._rg,
237
+ kind="Linux",
238
+ reserved=True,
239
+ sku=sku,
240
+ )
241
+
242
+ def _create_pgadmin_app(self):
243
+ # The app itself
244
+ app = azure.web.WebApp(
245
+ f"app-pgadmin-{self._name}",
246
+ resource_group_name=self._rg,
247
+ server_farm_id=self._app_service_plan.id,
248
+ virtual_network_subnet_id=self._app_subnet.id,
249
+ identity=azure.web.ManagedServiceIdentityArgs(
250
+ type=azure.web.ManagedServiceIdentityType.SYSTEM_ASSIGNED,
251
+ ),
252
+ https_only=True,
253
+ site_config=azure.web.SiteConfigArgs(
254
+ ftps_state=azure.web.FtpsState.DISABLED,
255
+ linux_fx_version="DOCKER|dpage/pgadmin4",
256
+ health_check_path="/misc/ping",
257
+ app_settings=[
258
+ azure.web.NameValuePairArgs(name="DOCKER_REGISTRY_SERVER_URL", value="https://index.docker.io/v1"),
259
+ azure.web.NameValuePairArgs(name="DOCKER_ENABLE_CI", value="true"),
260
+ # azure.web.NameValuePairArgs(name="WEBSITE_HTTPLOGGING_RETENTION_DAYS", value="7"),
261
+ # pgAdmin settings
262
+ azure.web.NameValuePairArgs(name="PGADMIN_DISABLE_POSTFIX", value="true"),
263
+ azure.web.NameValuePairArgs(name="PGADMIN_AUTHENTICATION_SOURCES", value="['oauth2, 'internal']"),
264
+ azure.web.NameValuePairArgs(name="PGADMIN_OAUTH2_NAME", value="azure"),
265
+ azure.web.NameValuePairArgs(name="PGADMIN_DEFAULT_EMAIL", value="dbadmin@dbadmin.net"),
266
+ azure.web.NameValuePairArgs(name="PGADMIN_DEFAULT_PASSWORD", value="dbadmin"),
267
+ ],
268
+ ),
269
+ )
270
+
271
+ # Create a storage container for persistent data (SMB share)
272
+ share = azure.storage.FileShare(
273
+ f"share-pgadmin-{self._name}",
274
+ resource_group_name=self._rg,
275
+ account_name=self._storage_account.name,
276
+ share_name="pgadmin",
277
+ )
278
+
279
+ # Mount the storage container
280
+ azure.web.WebAppAzureStorageAccounts(
281
+ f"app-pgadmin-mount-{self._name}",
282
+ resource_group_name=self._rg,
283
+ name=app.name,
284
+ properties={
285
+ "pgadmin-data": azure.web.AzureStorageInfoValueArgs(
286
+ account_name=self._storage_account.name,
287
+ access_key=self._get_storage_account_access_keys(self._storage_account)[0].value,
288
+ mount_path="/var/lib/pgadmin",
289
+ share_name=share.name,
290
+ type=azure.web.AzureStorageType.AZURE_FILES,
291
+ )
292
+ },
293
+ )
294
+
295
+ pulumi.export("pgadmin_url", app.default_host_name.apply(lambda host: f"https://{host}"))
296
+
297
+ def _add_webapp_host(self, app: azure.web.WebApp, host: str, suffix: str):
298
+ """
299
+ Because of a circular dependency, we need to create the certificate and the binding in two steps.
300
+ First we create a binding without a certificate,
301
+ then we create the certificate and then we update the binding.
302
+
303
+ The certificate needs the binding, and the binding needs the thumbprint of the certificate.
304
+
305
+ See also: https://github.com/pulumi/pulumi-azure-native/issues/578
306
+
307
+ :param app: The web app
308
+ :param host: The host name
309
+ :param suffix: A suffix to make the resource name unique
310
+ """
311
+
312
+ safe_host = host.replace(".", "-")
313
+
314
+ try:
315
+ # Retrieve the existing binding - this will throw an exception if it doesn't exist
316
+ azure.web.get_web_app_host_name_binding(
317
+ resource_group_name=app.resource_group,
318
+ name=app.name,
319
+ host_name=host,
320
+ )
321
+
322
+ # Create a managed certificate
323
+ # This will work because the binding exists actually
324
+ certificate = azure.web.Certificate(
325
+ f"cert-{suffix}-{safe_host}",
326
+ resource_group_name=self._rg,
327
+ server_farm_id=app.server_farm_id,
328
+ canonical_name=host,
329
+ host_names=[host],
330
+ )
331
+
332
+ # Create a new binding, replacing the old one,
333
+ # with the certificate
334
+ azure.web.WebAppHostNameBinding(
335
+ f"host-binding-{suffix}-{safe_host}",
336
+ resource_group_name=self._rg,
337
+ name=app.name,
338
+ host_name=host,
339
+ ssl_state=azure.web.SslState.SNI_ENABLED,
340
+ thumbprint=certificate.thumbprint,
341
+ )
342
+ except Exception:
343
+ # Create a binding without a certificate
344
+ azure.web.WebAppHostNameBinding(
345
+ f"host-binding-{suffix}-{safe_host}",
346
+ resource_group_name=self._rg,
347
+ name=app.name,
348
+ host_name=host,
349
+ )
350
+
351
+ def _get_storage_account_access_keys(
352
+ self, storage_account: azure.storage.StorageAccount
353
+ ) -> Sequence[azure.storage.outputs.StorageAccountKeyResponse]:
354
+ """
355
+ Helper function to get the access keys for a storage account.
356
+
357
+ :param storage_account: The storage account
358
+ :return: The access keys
359
+ """
360
+ keys = pulumi.Output.all(self._rg, storage_account.name).apply(
361
+ lambda args: azure.storage.list_storage_account_keys(
362
+ resource_group_name=args[0],
363
+ account_name=args[1],
364
+ )
365
+ )
366
+
367
+ return keys.keys
368
+
369
+ def add_database_administrator(self, object_id: str, user_name: str):
370
+ """
371
+ Add an Entra ID as database administrator.
372
+
373
+ :param object_id: The object ID of the user
374
+ :param user_name: The user name (user@example.com)
375
+ """
376
+
377
+ azure.dbforpostgresql.Administrator(
378
+ # Must be random but a GUID
379
+ f"pgsql-admin-{user_name.replace('@', '_')}-{self._name}",
380
+ resource_group_name=self._rg,
381
+ server_name=self._pgsql.name,
382
+ object_id=object_id,
383
+ principal_name=user_name,
384
+ principal_type=azure.dbforpostgresql.PrincipalType.USER,
385
+ tenant_id=self._tenant_id,
386
+ )
387
+
388
+ def add_django_website(
389
+ self,
390
+ name: str,
391
+ db_name: str,
392
+ repository_url: str,
393
+ repository_branch: str,
394
+ website_hosts: list[str],
395
+ django_settings_module: str,
396
+ environment_variables: dict[str, str] = {},
397
+ ) -> azure.web.WebApp:
398
+ """
399
+ Create a Django website with it's own database and storage containers.
400
+
401
+ :param name: The reference for the website, will be used to name subresources.
402
+ :param db_name: The name of the database to create.
403
+ :param repository_url: The URL of the Git repository.
404
+ :param repository_branch: The Git branch to deploy.
405
+ :param website_hosts: The list of custom host names for the website.
406
+ :param django_settings_module: The Django settings module to load.
407
+ :param environment_variables: A dictionary of environment variables to set.
408
+ """
409
+
410
+ # Create a database
411
+ db = azure.dbforpostgresql.Database(
412
+ f"db-{name}",
413
+ database_name=db_name,
414
+ resource_group_name=self._rg,
415
+ server_name=self._pgsql.name,
416
+ )
417
+
418
+ # Container for media files
419
+ media_container = azure.storage.BlobContainer(
420
+ f"storage-container-{name}-media-{self._name}",
421
+ resource_group_name=self._rg,
422
+ account_name=self._storage_account.name,
423
+ public_access=azure.storage.PublicAccess.BLOB,
424
+ container_name=f"{name}-media",
425
+ )
426
+
427
+ # Container for static files
428
+ static_container = azure.storage.BlobContainer(
429
+ f"storage-container-{name}-static-{self._name}",
430
+ resource_group_name=self._rg,
431
+ account_name=self._storage_account.name,
432
+ public_access=azure.storage.PublicAccess.BLOB,
433
+ container_name=f"{name}-static",
434
+ )
435
+
436
+ # Create a Django Secret Key (random)
437
+ secret_key = pulumi_random.RandomString(f"django-secret-{name}-{self._name}", length=50)
438
+
439
+ # Convert environment variables to NameValuePairArgs
440
+ environment_variables = [
441
+ azure.web.NameValuePairArgs(
442
+ name=key,
443
+ value=value,
444
+ )
445
+ for key, value in environment_variables.items()
446
+ ]
447
+
448
+ app = azure.web.WebApp(
449
+ f"app-{name}-{self._name}",
450
+ resource_group_name=self._rg,
451
+ server_farm_id=self._app_service_plan.id,
452
+ virtual_network_subnet_id=self._app_subnet.id,
453
+ identity=azure.web.ManagedServiceIdentityArgs(
454
+ type=azure.web.ManagedServiceIdentityType.SYSTEM_ASSIGNED,
455
+ ),
456
+ https_only=True,
457
+ site_config=azure.web.SiteConfigArgs(
458
+ always_on=True,
459
+ health_check_path=self.HEALTH_CHECK_PATH,
460
+ ftps_state=azure.web.FtpsState.DISABLED,
461
+ python_version="3.12",
462
+ # scm_type=azure.web.ScmType.EXTERNAL_GIT,
463
+ linux_fx_version="PYTHON|3.12",
464
+ app_settings=[
465
+ # Build settings
466
+ azure.web.NameValuePairArgs(name="SCM_DO_BUILD_DURING_DEPLOYMENT", value="true"),
467
+ azure.web.NameValuePairArgs(name="PRE_BUILD_COMMAND", value="cicd/pre_build.sh"),
468
+ azure.web.NameValuePairArgs(name="POST_BUILD_COMMAND", value="cicd/post_build.sh"),
469
+ azure.web.NameValuePairArgs(name="DISABLE_COLLECTSTATIC", value="true"),
470
+ azure.web.NameValuePairArgs(name="HEALTH_CHECK_PATH", value=self.HEALTH_CHECK_PATH),
471
+ # Django settings
472
+ # azure.web.NameValuePairArgs(name="DEBUG", value="true"),
473
+ azure.web.NameValuePairArgs(name="DJANGO_SETTINGS_MODULE", value=django_settings_module),
474
+ azure.web.NameValuePairArgs(name="DJANGO_SECRET_KEY", value=secret_key.result),
475
+ azure.web.NameValuePairArgs(name="DJANGO_ALLOWED_HOSTS", value=",".join(website_hosts)),
476
+ # Storage settings
477
+ azure.web.NameValuePairArgs(name="AZURE_STORAGE_ACCOUNT_NAME", value=self._storage_account.name),
478
+ azure.web.NameValuePairArgs(name="AZURE_STORAGE_CONTAINER_STATICFILES", value=static_container.name),
479
+ azure.web.NameValuePairArgs(name="AZURE_STORAGE_CONTAINER_MEDIA", value=media_container.name),
480
+ # CDN
481
+ azure.web.NameValuePairArgs(name="CDN_HOST", value=self._cdn_host),
482
+ # Database settings
483
+ azure.web.NameValuePairArgs(name="DB_HOST", value=self._pgsql.fully_qualified_domain_name),
484
+ azure.web.NameValuePairArgs(name="DB_NAME", value=db.name),
485
+ azure.web.NameValuePairArgs(name="DB_USER", value=f"{name}_managed_identity"),
486
+ *environment_variables,
487
+ ],
488
+ ),
489
+ )
490
+
491
+ # We need this to create the database role and grant permissions
492
+ principal_id = app.identity.apply(lambda identity: identity.principal_id)
493
+ pulumi.export(f"{name}_site_principal_id", principal_id)
494
+ pulumi.export(f"{name}_site_db_user", f"{name}_managed_identity")
495
+
496
+ # We need this to verify custom domains
497
+ pulumi.export(f"{name}_site_domain_verification_id", app.custom_domain_verification_id)
498
+ pulumi.export(f"{name}_site_domain_cname", app.default_host_name)
499
+
500
+ for host in website_hosts:
501
+ self._add_webapp_host(app=app, host=host, suffix=f"{name}-{self._name}")
502
+
503
+ # To enable deployment from GitLab
504
+ azure.web.WebAppSourceControl(
505
+ f"app-{name}-sourcecontrol-{self._name}",
506
+ resource_group_name=self._rg,
507
+ name=app.name,
508
+ repo_url=repository_url,
509
+ branch=repository_branch,
510
+ is_git_hub_action=False,
511
+ is_manual_integration=True,
512
+ is_mercurial=False,
513
+ )
514
+
515
+ # Where we can retrieve the SSH key
516
+ pulumi.export(
517
+ f"{name}_deploy_ssh_key_url", app.name.apply(lambda name: f"https://{name}.scm.azurewebsites.net/api/sshkey?ensurePublicKey=1")
518
+ )
519
+
520
+ # Find the role for Storage Blob Data Contributor
521
+ storage_role = self._storage_account.id.apply(
522
+ lambda scope: azure.authorization.get_role_definition(
523
+ role_definition_id="ba92f5b4-2d11-453d-a403-e96b0029c9fe",
524
+ scope=scope,
525
+ )
526
+ )
527
+
528
+ # Grant the app access to the storage account
529
+ azure.authorization.RoleAssignment(
530
+ f"ra-{name}-storage",
531
+ principal_id=principal_id,
532
+ principal_type=azure.authorization.PrincipalType.SERVICE_PRINCIPAL,
533
+ role_definition_id=storage_role.id,
534
+ scope=self._storage_account.id,
535
+ )
536
+
537
+ # Create a CORS rules for this website
538
+ if website_hosts:
539
+ origins = [f"https://{host}" for host in website_hosts]
540
+ else:
541
+ origins = ["*"]
542
+
543
+ azure.storage.BlobServiceProperties(
544
+ f"sa-{name}-blob-properties",
545
+ resource_group_name=self._rg,
546
+ account_name=self._storage_account.name,
547
+ blob_services_name="default",
548
+ cors=azure.storage.CorsRulesArgs(
549
+ cors_rules=[
550
+ azure.storage.CorsRuleArgs(
551
+ allowed_headers=["*"],
552
+ allowed_methods=["GET", "OPTIONS", "HEAD"],
553
+ allowed_origins=origins,
554
+ exposed_headers=["Access-Control-Allow-Origin"],
555
+ max_age_in_seconds=86400,
556
+ )
557
+ ]
558
+ ),
559
+ )
560
+
561
+ return app
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pulumi-django-azure
3
- Version: 1.0.2
3
+ Version: 1.0.4
4
4
  Summary: Simply deployment of Django on Azure with Pulumi
5
5
  Author-email: Maarten Ureel <maarten@youreal.eu>
6
6
  License: MIT License
@@ -0,0 +1,7 @@
1
+ pulumi_django_azure/__init__.py,sha256=tXTvPfr8-Nll5cjMyY9yj_0z_PQ0XAcxihzHRCES-hU,63
2
+ pulumi_django_azure/django_deployment.py,sha256=yvpOUkcHs37Mb2xTD6BqtB21opxTvFLQzRxMHXTK2aY,23410
3
+ pulumi_django_azure-1.0.4.dist-info/LICENSE,sha256=NX2LN3U319Zaac8b7ZgfNOco_nTBbN531X_M_13niSg,1087
4
+ pulumi_django_azure-1.0.4.dist-info/METADATA,sha256=25RH8tZL2LrhBjuYRngUcRArER9TiAorLEaCJulFhLA,7887
5
+ pulumi_django_azure-1.0.4.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
6
+ pulumi_django_azure-1.0.4.dist-info/top_level.txt,sha256=MNPRJhq-_G8EMCHRkjdcb_xrqzOkmKogXUGV7Ysz3g0,20
7
+ pulumi_django_azure-1.0.4.dist-info/RECORD,,
@@ -0,0 +1 @@
1
+ pulumi_django_azure
@@ -1,5 +0,0 @@
1
- pulumi_django_azure-1.0.2.dist-info/LICENSE,sha256=NX2LN3U319Zaac8b7ZgfNOco_nTBbN531X_M_13niSg,1087
2
- pulumi_django_azure-1.0.2.dist-info/METADATA,sha256=PSuScGCzqH0jEnkJmnhctwI-63jiFlVq5Ni5DCmURLA,7887
3
- pulumi_django_azure-1.0.2.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
4
- pulumi_django_azure-1.0.2.dist-info/top_level.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
5
- pulumi_django_azure-1.0.2.dist-info/RECORD,,