Exemplo n.º 1
0
        public static void SetupBlobStorageRepository(FeatureContext featureContext)
        {
            IServiceProvider serviceProvider = ContainerBindings.GetServiceProvider(featureContext);
            IBlobContainerSourceWithTenantLegacyTransition factory = serviceProvider.GetRequiredService <IBlobContainerSourceWithTenantLegacyTransition>();
            ITenantProvider tenantProvider = serviceProvider.GetRequiredService <ITenantProvider>();
            IConfiguration  configuration  = serviceProvider.GetRequiredService <IConfiguration>();

            ITenant rootTenant = tenantProvider.Root;

            LegacyV2BlobStorageConfiguration storageConfig =
                configuration.GetSection("TestStorageConfiguration").Get <LegacyV2BlobStorageConfiguration>()
                ?? new LegacyV2BlobStorageConfiguration();

            // Generate a container name just for this test, otherwise you can end up with collisions
            // on subsequent tests runs while containers are still being deleted.
            storageConfig.Container = Guid.NewGuid().ToString();

            tenantProvider.Root.UpdateProperties(data => data.Append(new KeyValuePair <string, object>(
                                                                         "StorageConfiguration__workflowdefinitions",
                                                                         storageConfig)));
        }
Exemplo n.º 2
0
        private static BlobContainerConfiguration V3ConfigurationFromLegacy(
            ITenant tenant,
            string?containerName,
            LegacyV2BlobStorageConfiguration legacyConfiguration)
        {
            BlobContainerConfiguration v3Configuration = LegacyConfigurationConverter.FromV2ToV3(legacyConfiguration);

            if (legacyConfiguration.Container is not null)
            {
                v3Configuration = v3Configuration with
                {
                    Container = string.IsNullOrWhiteSpace(legacyConfiguration.Container)
                        ? containerName is null ? null : AzureStorageBlobContainerNaming.HashAndEncodeBlobContainerName(containerName)
                            : AzureStorageBlobContainerNaming.HashAndEncodeBlobContainerName(
                        legacyConfiguration.DisableTenantIdPrefix
                                ? legacyConfiguration.Container
                                : AzureStorageBlobTenantedContainerNaming.GetTenantedLogicalBlobContainerNameFor(tenant, legacyConfiguration.Container)),
                };
            }

            return(AddContainerNameIfNotInConfig(v3Configuration, containerName));
        }
        /// <inheritdoc/>
        public async Task <ITenant> CreateWellKnownChildTenantAsync(
            string parentTenantId,
            Guid wellKnownChildTenantGuid,
            string name)
        {
            (ITenant parentTenant, BlobContainerClient container) =
                await this.GetContainerAndTenantForChildTenantsOfAsync(parentTenantId).ConfigureAwait(false);

            // We need to copy blob storage settings for the Tenancy container definition from the parent to the new child
            // to support the tenant blob store provider. We would expect this to be overridden by clients that wanted to
            // establish their own settings.
            bool configIsInV3 = true;
            LegacyV2BlobStorageConfiguration?v2TenancyStorageConfiguration = null;

            if (!parentTenant.Properties.TryGet(TenancyV3ConfigKey, out BlobContainerConfiguration tenancyStorageConfiguration))
            {
                configIsInV3 = false;
                if (!parentTenant.Properties.TryGet(TenancyV2ConfigKey, out v2TenancyStorageConfiguration))
                {
                    throw new InvalidOperationException($"No configuration found for ${TenancyV3ConfigKey} or ${TenancyV2ConfigKey}");
                }
            }

            IPropertyBag childProperties;

            if (parentTenantId == this.Root.Id && this.propagateRootStorageConfigAsV2)
            {
                configIsInV3 = false;
                v2TenancyStorageConfiguration = new LegacyV2BlobStorageConfiguration
                {
                    Container = tenancyStorageConfiguration.Container,
                };
                if (tenancyStorageConfiguration.ConnectionStringPlainText != null)
                {
                    v2TenancyStorageConfiguration.AccountName = tenancyStorageConfiguration.ConnectionStringPlainText;
                }
                else if (tenancyStorageConfiguration.AccountName != null)
                {
                    v2TenancyStorageConfiguration.AccountName          = tenancyStorageConfiguration.AccountName;
                    v2TenancyStorageConfiguration.KeyVaultName         = tenancyStorageConfiguration.AccessKeyInKeyVault?.VaultName;
                    v2TenancyStorageConfiguration.AccountKeySecretName = tenancyStorageConfiguration.AccessKeyInKeyVault?.SecretName;
                }
            }

            if (configIsInV3)
            {
                childProperties = this.propertyBagFactory.Create(values =>
                                                                 values.Append(new KeyValuePair <string, object>(TenancyV3ConfigKey, tenancyStorageConfiguration)));
            }
            else
            {
                childProperties = this.propertyBagFactory.Create(values =>
                                                                 values.Append(new KeyValuePair <string, object>(TenancyV2ConfigKey, v2TenancyStorageConfiguration !)));
            }

            var child = new Tenant(
                parentTenantId.CreateChildId(wellKnownChildTenantGuid),
                name,
                childProperties);

            // TODO: this needs thinking through.
            BlobContainerClient newTenantBlobContainer = await this.GetBlobContainer(child).ConfigureAwait(false);

            await newTenantBlobContainer.CreateIfNotExistsAsync().ConfigureAwait(false);

            // As we create the new blob, we need to ensure there isn't already a tenant with the same Id. We do this by
            // providing an If-None-Match header passing a "*", which will cause a storage exception with a 409 status
            // code if a blob with the same Id already exists.
            BlockBlobClient blob    = GetLiveTenantBlockBlobReference(child.Id, container);
            var             content = new MemoryStream();

            using (var sw = new StreamWriter(content, UTF8WithoutBom, leaveOpen: true))
                using (JsonWriter writer = new JsonTextWriter(sw))
                {
                    this.jsonSerializer.Serialize(writer, child);
                }

            content.Position = 0;
            try
            {
                Response <BlobContentInfo> response = await blob.UploadAsync(
                    content,
                    new BlobUploadOptions { Conditions = new BlobRequestConditions {
                                                IfNoneMatch = ETag.All
                                            } })
                                                      .ConfigureAwait(false);

                child.ETag = response.Value.ETag.ToString("H");
            }
            catch (global::Azure.RequestFailedException x)
                when(x.ErrorCode == "BlobAlreadyExists")
                {
                    // This exception is thrown because there's already a tenant with the same Id. This should never happen when
                    // this method has been called from CreateChildTenantAsync as the Guid will have been generated and the
                    // chances of it matching one previously generated are miniscule. However, it could happen when calling this
                    // method directly with a wellKnownChildTenantGuid that's already in use. In this case, the fault is with
                    // the client code - creating tenants with well known Ids is something one would expect to happen under
                    // controlled conditions, so it's only likely that a conflict will occur when either the client code has made
                    // a mistake or someone is actively trying to cause problems.
                    throw new ArgumentException(
                              $"A child tenant of '{parentTenantId}' with a well known Guid of '{wellKnownChildTenantGuid}' already exists.",
                              nameof(wellKnownChildTenantGuid));
                }

            return(child);
        }