Esempio n. 1
0
            public async Task <GrainStateRecord> Read(string partitionKey, string rowKey)
            {
                if (logger.IsVerbose3)
                {
                    logger.Verbose3((int)AzureProviderErrorCode.AzureTableProvider_Storage_Reading, "Reading: PartitionKey={0} RowKey={1} from Table={2}", partitionKey, rowKey, TableName);
                }
                try
                {
                    Tuple <GrainStateEntity, string> data = await tableManager.ReadSingleTableEntryAsync(partitionKey, rowKey);

                    if (data == null || data.Item1 == null)
                    {
                        if (logger.IsVerbose2)
                        {
                            logger.Verbose2((int)AzureProviderErrorCode.AzureTableProvider_DataNotFound, "DataNotFound reading: PartitionKey={0} RowKey={1} from Table={2}", partitionKey, rowKey, TableName);
                        }
                        return(null);
                    }
                    GrainStateEntity stateEntity = data.Item1;
                    var record = new GrainStateRecord {
                        Entity = stateEntity, ETag = data.Item2
                    };
                    if (logger.IsVerbose3)
                    {
                        logger.Verbose3((int)AzureProviderErrorCode.AzureTableProvider_Storage_DataRead, "Read: PartitionKey={0} RowKey={1} from Table={2} with ETag={3}", stateEntity.PartitionKey, stateEntity.RowKey, TableName, record.ETag);
                    }
                    return(record);
                }
                catch (Exception exc)
                {
                    if (AzureStorageUtils.TableStorageDataNotFound(exc))
                    {
                        if (logger.IsVerbose2)
                        {
                            logger.Verbose2((int)AzureProviderErrorCode.AzureTableProvider_DataNotFound, "DataNotFound reading (exception): PartitionKey={0} RowKey={1} from Table={2} Exception={3}", partitionKey, rowKey, TableName, TraceLogger.PrintException(exc));
                        }
                        return(null);  // No data
                    }
                    throw;
                }
            }
Esempio n. 2
0
        public string WriteLog(PayPalLogEntity.NotificationKind kind, string txnId, string logData)
        {
            if (String.IsNullOrEmpty(txnId))
            {
                throw new ArgumentException();
            }

            var rowKey = KeyUtils.GetCurrentTimeKey();

            var entity = new PayPalLogEntity
            {
                PartitionKey = txnId,
                RowKey       = rowKey,
                Kind         = kind.ToString(),
                LogData      = logData,
            };

            AzureStorageUtils.InsertEntity(AzureStorageUtils.TableNames.PaymentLog, entity);

            return(rowKey);
        }
Esempio n. 3
0
        public async Task <IHttpActionResult> InboundWebhook(InboundWebhookFormModel form)
        {
            // The form is empty on a HEAD request
            if (form != null)
            {
                var mandrill_events = form.mandrill_events;
                var partitionKey    = KeyUtils.GetCurrentTimeKey();

                var entity = new ExternalSessionLogEntity
                {
                    PartitionKey = partitionKey,
                    RowKey       = "InboundWebhook",
                    Data         = mandrill_events,
                };
                await AzureStorageUtils.InsertEntityAsync(AzureStorageUtils.TableNames.ExternalSessions, entity);

                await SendSmsMessage("InboundWebhook " + partitionKey, partitionKey);
            }

            return(StatusCode(HttpStatusCode.NoContent));
        }
Esempio n. 4
0
        public async Task <IHttpActionResult> GetAllReviewPieces(int exerciseId)
        {
            var filterPartition = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, ReviewPiece.GetPartitionKey(exerciseId));
            var query           = new TableQuery <ReviewPiece>().Where(filterPartition);
            var allPieces       = await AzureStorageUtils.ExecuteQueryAsync(AzureStorageUtils.TableNames.ReviewPieces, query);

            // Enforce access rights. The exercise author cannot see review items in an unfinished review. An access entity is written when a review is finished. See ReviewsApiController.PostFinishReview
            var userAccessCode = ReviewPiece.PieceTypes.Viewer + KeyUtils.IntToKey(this.GetUserId());
            // Find the ReviewIds which are allowed to access.
            var reviewIds = allPieces
                            .Where(i => ReviewPiece.GetUserAccessCode(i.RowKey) == userAccessCode)
                            .Select(i => ReviewPiece.GetReviewId(i.RowKey))
                            .ToList();

            RemoveAccessEntries(allPieces);

            // Filter the record set.
            var accessablePieces = allPieces.Where(i => reviewIds.Contains(ReviewPiece.GetReviewId(i.RowKey)));
            var piecesArr        = accessablePieces.Select(i => i.Json).ToArray();

            return(Ok(piecesArr));
        }
Esempio n. 5
0
        public async Task <ActionResult> Claim(string id)
        {
            var userIdKey    = KeyUtils.IntToKey(0);
            var longTimeKey  = id + this.GetExtId();
            var blobName     = ExerciseUtils.FormatBlobName(userIdKey, longTimeKey, "metadata", "json");
            var blob         = AzureStorageUtils.GetBlob(AzureStorageUtils.ContainerNames.Artifacts, blobName);
            var metadataJson = await blob.DownloadTextAsync();

            var metadata         = JObject.Parse(metadataJson);
            var serviceType      = (string)metadata["serviceType"];
            var cardId           = (Guid?)metadata["cardId"];
            var title            = (string)metadata["title"];
            var comment          = (string)metadata["comment"];
            var details          = metadata["recordingDetails"];
            var recordingDetails = details.ToObject <RecordingDetails>();

            var exerciseId = await ExerciseUtils.CreateExercise(recordingDetails.BlobName, this.GetUserId(),
                                                                serviceType, ArtifactType.Mp3, recordingDetails.TotalDuration, title, cardId, comment, details.ToString(Formatting.None));

            //~~ Redirect to the View exercise page.
            return(RedirectToAction("View", new { Id = exerciseId }));
        }
Esempio n. 6
0
        private async Task ExecuteQueryAsync(string processName, TableQuery <T> rangeQuery, Func <T, bool> filter,
                                             Func <IEnumerable <T>, Task> yieldData)
        {
            try
            {
                TableContinuationToken tableContinuationToken = null;
                var table = GetTable();
                do
                {
                    var queryResponse = await table.ExecuteQuerySegmentedAsync(rangeQuery, tableContinuationToken);

                    tableContinuationToken = queryResponse.ContinuationToken;
                    await yieldData(AzureStorageUtils.ApplyFilter(queryResponse.Results, filter));
                } while (tableContinuationToken != null);
            }
            catch (Exception ex)
            {
                _log?.WriteFatalError("Table storage: " + _tableName, processName, rangeQuery.FilterString ?? "[null]",
                                      ex).Wait();
                throw;
            }
        }
Esempio n. 7
0
 public Task InsertAsync(IEnumerable <T> items)
 {
     items = items.ToArray();
     try
     {
         if (items.Any())
         {
             var insertBatchOperation = new TableBatchOperation();
             foreach (var item in items)
             {
                 insertBatchOperation.Insert(item);
             }
             return(GetTable().ExecuteBatchAsync(insertBatchOperation));
         }
     }
     catch (Exception ex)
     {
         _log?.WriteFatalError("Table storage: " + _tableName, "InsertAsync batch",
                               AzureStorageUtils.PrintItems(items), ex);
     }
     return(Task.CompletedTask);
 }
Esempio n. 8
0
        public async Task AQ_Standalone_1()
        {
            queueName = "Test-1-".ToLower() + Guid.NewGuid();
            AzureQueueDataManager manager = await GetTableManager(queueName);

            Assert.AreEqual(0, await manager.GetApproximateMessageCount());

            CloudQueueMessage inMessage = new CloudQueueMessage("Hello, World");
            await manager.AddQueueMessage(inMessage);

            //Nullable<int> count = manager.ApproximateMessageCount;
            Assert.AreEqual(1, await manager.GetApproximateMessageCount());

            CloudQueueMessage outMessage1 = await manager.PeekQueueMessage();

            logger.Info("PeekQueueMessage 1: {0}", AzureStorageUtils.PrintCloudQueueMessage(outMessage1));
            Assert.AreEqual(inMessage.AsString, outMessage1.AsString);

            CloudQueueMessage outMessage2 = await manager.PeekQueueMessage();

            logger.Info("PeekQueueMessage 2: {0}", AzureStorageUtils.PrintCloudQueueMessage(outMessage2));
            Assert.AreEqual(inMessage.AsString, outMessage2.AsString);

            CloudQueueMessage outMessage3 = await manager.GetQueueMessage();

            logger.Info("GetQueueMessage 3: {0}", AzureStorageUtils.PrintCloudQueueMessage(outMessage3));
            Assert.AreEqual(inMessage.AsString, outMessage3.AsString);
            Assert.AreEqual(1, await manager.GetApproximateMessageCount());

            CloudQueueMessage outMessage4 = await manager.GetQueueMessage();

            Assert.IsNull(outMessage4);

            Assert.AreEqual(1, await manager.GetApproximateMessageCount());

            await manager.DeleteQueueMessage(outMessage3);

            Assert.AreEqual(0, await manager.GetApproximateMessageCount());
        }
Esempio n. 9
0
        public async Task <IHttpActionResult> DeletePiece(string partitionKey, string rowKey)
        {
            // Check access rights.
            var reviewId     = ReviewPiece.GetReviewId(rowKey);
            var table        = AzureStorageUtils.GetCloudTable(AzureStorageUtils.TableNames.ReviewPieces);
            var userIsEditor = await UserIsEditor(partitionKey, reviewId, table);

            if (userIsEditor)
            {
                var entity = new ReviewPiece()
                {
                    PartitionKey = partitionKey,
                    RowKey       = rowKey,
                    ETag         = "*",
                };
                var deleteOperation = TableOperation.Delete(entity);
                // If the piece is not yet saved, we will get "The remote server returned an error: (404) Not Found."
                // The approved solution from MS is to try to retrieve the entity first. Catching exception is a hack which is appropriate for a single entity, it is not compatible with a Batch operation.
                try
                {
                    await table.ExecuteAsync(deleteOperation);
                }
                catch (StorageException ex)
                {
                    if (ex.RequestInformation.HttpStatusCode != (int)HttpStatusCode.NotFound)
                    {
                        throw;
                    }
                }

                // Notify the exercise author in real-time.
                var pieceType = ReviewPiece.GetType(rowKey);
                var pieceId   = ReviewPiece.GetPieceId(rowKey);
                this.GetAuthorConnections(partitionKey).PieceDeleted(reviewId, pieceType, pieceId);
            }

            return(StatusCode(userIsEditor ? HttpStatusCode.NoContent : HttpStatusCode.BadRequest));
        }
        public async Task PublishAssetAsync(string file, string blobPath, PushOptions options, SemaphoreSlim clientThrottle = null)
        {
            using (await SemaphoreLock.LockAsync(clientThrottle))
            {
                blobPath = blobPath.Replace("\\", "/");
                var blobClient = CreateBlobClient(blobPath);
                if (!options.AllowOverwrite && await blobClient.ExistsAsync())
                {
                    if (options.PassIfExistingItemIdentical)
                    {
                        if (!await blobClient.IsFileIdenticalToBlobAsync(file))
                        {
                            _log.LogError($"Asset '{file}' already exists with different contents at '{blobPath}'");
                        }

                        return;
                    }

                    _log.LogError($"Asset '{file}' already exists at '{blobPath}'");
                    return;
                }

                _log.LogMessage($"Uploading '{file}' to '{blobPath}'");

                try
                {
                    BlobUploadOptions blobUploadOptions = new()
                    {
                        HttpHeaders = AzureStorageUtils.GetBlobHeadersByExtension(file)
                    };
                    await blobClient.UploadAsync(file, blobUploadOptions);
                }
                catch (Exception e)
                {
                    _log.LogError($"Unexpected exception publishing file {file} to {blobPath}: {e.Message}");
                }
            }
        }
        public void AzureTableErrorCode_ExtractRestErrorCode_ServerBusy()
        {
            string xml =
                "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" +
                "<error xmlns=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\">" +
                "<code>ServerBusy</code>" +
                "<message xml:lang=\"en-US\">The server is busy." +
                "RequestId:14ab4de6-fe80-4a45-a364-b0c2a27a4a86" +
                "Time:2013-09-24T23:29:13.4913945Z</message>" +
                "</error>";

            var exc     = new DataServiceClientException(xml);
            var strCode = AzureStorageUtils.ExtractRestErrorCode(exc);

            Assert.AreEqual(StorageErrorCodeStrings.ServerBusy, strCode);

            var wrapped = new AggregateException(exc);

            strCode = AzureStorageUtils.ExtractRestErrorCode(wrapped);
            Assert.AreEqual(StorageErrorCodeStrings.ServerBusy, strCode);

            //Assert.IsTrue(Async_AzureTableDataManager<SiloMetricsData>.IsRetriableHttpError((HttpStatusCode)500, "ServerBusy"));
        }
Esempio n. 12
0
        // Extract text from the HTML page
        private string FindText(string html, string startSnippet, string endSnippet)
        {
            var i1 = html.IndexOf(startSnippet);
            var i2 = html.IndexOf(endSnippet, i1 + 1);

            if ((i1 == -1) || (i2 == -1))
            {
                // Write the poison HTML page to the log.
                var partitionKey = KeyUtils.GetCurrentTimeKey();
                var entity       = new ExternalSessionLogEntity
                {
                    PartitionKey = partitionKey,
                    RowKey       = "Error_FindText",
                    Data         = html,
                };
                AzureStorageUtils.InsertEntity(AzureStorageUtils.TableNames.ExternalSessions, entity);

                throw new FormatException("Parsing the external service data. Snippet not found. " + startSnippet.Length.ToString() + " " + endSnippet.Length.ToString());
            }
            var shift = startSnippet.Length;

            return(html.Substring(i1 + shift, i2 - i1 - shift));
        }
Esempio n. 13
0
        public async Task DeleteAsync(IEnumerable <T> items)
        {
            items = items.ToArray();
            try
            {
                if (items.Any())
                {
                    var deleteBatchOperation = new TableBatchOperation();
                    foreach (var item in items)
                    {
                        deleteBatchOperation.Delete(item);
                    }
                    var table = await GetTable();

                    await table.ExecuteBatchAsync(deleteBatchOperation);
                }
            }
            catch (Exception ex)
            {
                _log?.WriteFatalErrorAsync("Table storage: " + _tableName, "DeleteAsync batch",
                                           AzureStorageUtils.PrintItems(items), ex);
            }
        }
Esempio n. 14
0
        private async Task <DapperHelper.PageItems <ResourceDto> > GetHistoryResources(int userId, string secondaryFilter, int offset = 0, int limit = 0)
        {
            var result = new DapperHelper.PageItems <ResourceDto>();

            var partitionKey    = KeyUtils.IntToKey(userId);
            var filterPartition = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey);
            var combinedFilter  = !String.IsNullOrEmpty(secondaryFilter) ? TableQuery.CombineFilters(filterPartition, TableOperators.And, secondaryFilter) : filterPartition;
            var query           = new TableQuery <LibraryHistoryEntity>().Where(combinedFilter);
            var entities        = await AzureStorageUtils.ExecuteQueryAsync(AzureStorageUtils.TableNames.LibraryHistory, query);

            result.TotalCount = entities.Count();

            if (entities.Any())
            {
                var historyItems = (limit != 0)
                        ? entities.Skip(offset).Take(limit)
                        : entities;

                result.Items = await HydrateHistoryItems(historyItems, userId);
            }

            return(result);
        }
Esempio n. 15
0
        // GET: /history
        public async Task <ActionResult> History()
        {
            // Send all the days there are records for. We will enable/disable days in the calendar on the page accordingly. RowKeys in the table are "inverted" local time.
            var days = new List <string>();

            if (this.IsAuthenticated())
            {
                var userId          = this.GetUserId();
                var partitionKey    = KeyUtils.IntToKey(userId);
                var filterPartition = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey);
                var query           = new TableQuery <TableEntity>().Where(filterPartition);
                var table           = AzureStorageUtils.GetCloudTable(AzureStorageUtils.TableNames.LibraryHistory);

                TableQuerySegment <TableEntity> currentSegment = null;
                while (currentSegment == null || currentSegment.ContinuationToken != null)
                {
                    currentSegment = await table.ExecuteQuerySegmentedAsync <TableEntity>(
                        query,
                        currentSegment != null?currentSegment.ContinuationToken : null
                        );

                    // Format 2014-01-21 as "140121"
                    var localDays = currentSegment.Results
                                    .GroupBy(i => i.RowKey.Substring(0, 6))
                                    .Select(i => KeyUtils.InvertedKeyToLocalTime(i.Key, 3, "", "d2").Substring(2))
                    ;

                    days.AddRange(localDays);
                }
            }

            //var daysParam = days.Distinct();
            //ViewBag.DaysParamJson = JsonUtils.SerializeAsJson(daysParam);
            ViewBag.DaysParam = days.Distinct();

            return(View());
        }
Esempio n. 16
0
 internal async Task <string> UpsertRow(ReminderTableEntry reminderEntry)
 {
     try
     {
         return(await UpsertTableEntryAsync(reminderEntry));
     }
     catch (Exception exc)
     {
         HttpStatusCode httpStatusCode;
         string         restStatus;
         if (AzureStorageUtils.EvaluateException(exc, out httpStatusCode, out restStatus))
         {
             if (Logger.IsEnabled(LogLevel.Trace))
             {
                 Logger.Trace("UpsertRow failed with httpStatusCode={0}, restStatus={1}", httpStatusCode, restStatus);
             }
             if (AzureStorageUtils.IsContentionError(httpStatusCode))
             {
                 return(null);                                                     // false;
             }
         }
         throw;
     }
 }
Esempio n. 17
0
        private IEnumerable <T> ExecuteQuery(string processName, TableQuery <T> rangeQuery, Func <T, bool> filter)
        {
            TableContinuationToken tableContinuationToken = null;

            do
            {
                TableQuerySegment <T> queryResponse;
                try
                {
                    queryResponse          = GetTable().ExecuteQuerySegmented(rangeQuery, tableContinuationToken);
                    tableContinuationToken = queryResponse.ContinuationToken;
                }
                catch (Exception ex)
                {
                    _log?.WriteFatalError("Table storage: " + _tableName, processName, rangeQuery.FilterString ?? "[null]", ex);
                    throw;
                }

                foreach (var itm in AzureStorageUtils.ApplyFilter(queryResponse.Results, filter))
                {
                    yield return(itm);
                }
            } while (tableContinuationToken != null);
        }
Esempio n. 18
0
        public async Task <IHttpActionResult> PutReviewPieces([FromBody] IEnumerable <ReviewPiece> pieces)
        {
            // All pieces must belong to the same exercise and review.
            var partitionKey = pieces
                               .Select(i => i.PartitionKey)
                               .GroupBy(i => i)
                               .Select(i => i.Key)
                               .Single();

            var reviewId = pieces
                           .Select(i => ReviewPiece.GetReviewId(i.RowKey))
                           .GroupBy(i => i)
                           .Select(i => i.Key)
                           .Single();

            // Ensure that the user is the actual reviewer. Check the presense of the access entry for the user. All pieces must belong to the same exercise and review.
            var table        = AzureStorageUtils.GetCloudTable(AzureStorageUtils.TableNames.ReviewPieces);
            var userIsEditor = await UserIsEditor(partitionKey, reviewId, table);

            if (userIsEditor)
            {
                var batchOperation = new TableBatchOperation();
                foreach (var piece in pieces)
                {
                    batchOperation.InsertOrReplace(piece);
                }
                await table.ExecuteBatchAsync(batchOperation);
            }

            // Notify the exercise author in real-time.
            var piecesArr = pieces.Select(i => i.Json).ToArray();

            this.GetAuthorConnections(partitionKey).PiecesChanged(piecesArr);

            return(StatusCode(userIsEditor ? HttpStatusCode.NoContent : HttpStatusCode.BadRequest));
        }
Esempio n. 19
0
        public void AzureTableErrorCode_BadTableName()
        {
            string tableName = "abc-123";

            AzureStorageUtils.ValidateTableName(tableName);
        }
Esempio n. 20
0
        public static string MakeRowKey(string partition)
        {
            string key = $"partition_{partition}";

            return(AzureStorageUtils.SanitizeTableProperty(key));
        }
Esempio n. 21
0
        public static string MakePartitionKey(string streamProviderName, string checkpointNamespace)
        {
            string key = $"EventHubCheckpoints_{streamProviderName}_{checkpointNamespace}";

            return(AzureStorageUtils.SanitizeTableProperty(key));
        }
Esempio n. 22
0
 public Task <IEnumerable <T> > GetDataAsync(string partition, Func <T, bool> filter = null)
 {
     return(Task.Run(() => AzureStorageUtils.ApplyFilter(this[partition], filter)));
 }
Esempio n. 23
0
        public async Task InsertAsync(T item, params int[] notLogCodes)
        {
            await _lockSlim.WaitAsync();

            try
            {
                if (HasElement(item))
                {
                    var message =
                        string.Format("Can not insert. Item is already in the table. Data:{0}", AzureStorageUtils.PrintItem(item));

                    var exception = StorageException.TranslateException(new Exception(message),

                                                                        new RequestResult
                    {
                        HttpStatusCode = AzureStorageUtils.Conflict
                    }

                                                                        );

                    throw exception;
                }
                PrivateInsert(item);
            }
            finally
            {
                _lockSlim.Release();
            }
        }
Esempio n. 24
0
 /// <summary> Decodes Storage exceptions.</summary>
 public bool DecodeException(Exception e, out HttpStatusCode httpStatusCode, out string restStatus, bool getRESTErrors = false)
 {
     return(AzureStorageUtils.EvaluateException(e, out httpStatusCode, out restStatus, getRESTErrors));
 }
Esempio n. 25
0
        private string GetKeyString(GrainReference grainReference)
        {
            var key = String.Format("{0}_{1}", this.clusterOptions.ServiceId, grainReference.ToKeyString());

            return(AzureStorageUtils.SanitizeTableProperty(key));
        }
Esempio n. 26
0
        }                                                     // Part of PartitionKey


        public static string ConstructRowKey(GrainReference grainRef, string reminderName)
        {
            var key = String.Format("{0}-{1}", grainRef.ToKeyString(), reminderName); //grainRef.ToString(), reminderName);

            return(AzureStorageUtils.SanitizeTableProperty(key));
        }
Esempio n. 27
0
        public static string MakeRowKey(string partition)
        {
            string key = String.Format("partition_{0}", partition);

            return(AzureStorageUtils.SanitizeTableProperty(key));
        }
Esempio n. 28
0
        public async Task AzureTableDataManager_UpdateTableEntryAsync()
        {
            var data = GenerateNewData();

            try
            {
                await manager.UpdateTableEntryAsync(data, AzureStorageUtils.ANY_ETAG);

                Assert.True(false, "Should have thrown StorageException.");
            }
            catch (StorageException exc)
            {
                Assert.Equal((int)HttpStatusCode.NotFound, exc.RequestInformation.HttpStatusCode);  // "Update before insert."
                HttpStatusCode httpStatusCode;
                string         restStatus;
                AzureStorageUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);
                Assert.Equal(HttpStatusCode.NotFound, httpStatusCode);
                Assert.Equal(StorageErrorCodeStrings.ResourceNotFound, restStatus);
            }

            await manager.UpsertTableEntryAsync(data);

            var tuple = await manager.ReadSingleTableEntryAsync(data.PartitionKey, data.RowKey);

            Assert.Equal(data.StringData, tuple.Item1.StringData);

            var data2 = data.Clone();

            data2.StringData = "NewData";
            string eTag1 = await manager.UpdateTableEntryAsync(data2, AzureStorageUtils.ANY_ETAG);

            tuple = await manager.ReadSingleTableEntryAsync(data2.PartitionKey, data2.RowKey);

            Assert.Equal(data2.StringData, tuple.Item1.StringData);

            var data3 = data.Clone();

            data3.StringData = "EvenNewerData";
            string ignoredETag = await manager.UpdateTableEntryAsync(data3, eTag1);

            tuple = await manager.ReadSingleTableEntryAsync(data3.PartitionKey, data3.RowKey);

            Assert.Equal(data3.StringData, tuple.Item1.StringData);

            try
            {
                string eTag3 = await manager.UpdateTableEntryAsync(data3.Clone(), eTag1);

                Assert.True(false, "Should have thrown StorageException.");
            }
            catch (StorageException exc)
            {
                Assert.Equal((int)HttpStatusCode.PreconditionFailed, exc.RequestInformation.HttpStatusCode);  // "Wrong eTag"
                HttpStatusCode httpStatusCode;
                string         restStatus;
                AzureStorageUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);
                Assert.Equal(HttpStatusCode.PreconditionFailed, httpStatusCode);
                Assert.True(restStatus == TableErrorCodeStrings.UpdateConditionNotSatisfied ||
                            restStatus == StorageErrorCodeStrings.ConditionNotMet, restStatus);
            }
        }
Esempio n. 29
0
        /// <summary>
        ///     Determine whether a local package is the same as a package on an AzDO feed.
        /// </summary>
        /// <param name="localPackageFullPath"></param>
        /// <param name="packageContentUrl"></param>
        /// <param name="client"></param>
        /// <returns></returns>
        /// <remarks>
        ///     Open a stream to the local file and an http request to the package. There are a couple possibilities:
        ///     - The returned headers includes a content MD5 header, in which case we can
        ///       hash the local file and just compare those.
        ///     - No content MD5 hash, and the streams must be compared in blocks. This is a bit trickier to do efficiently,
        ///       since we do not necessarily want to read all bytes if we can help it. Thus, we should compare in blocks.  However,
        ///       the streams make no gaurantee that they will return a full block each time when read operations are performed, so we
        ///       must be sure to only compare the minimum number of bytes returned.
        /// </remarks>
        public static async Task <PackageFeedStatus> CompareLocalPackageToFeedPackage(string localPackageFullPath, string packageContentUrl, HttpClient client, TaskLoggingHelper log)
        {
            log.LogMessage($"Getting package content from {packageContentUrl} and comparing to {localPackageFullPath}");

            PackageFeedStatus result = PackageFeedStatus.Unknown;

            ExponentialRetry RetryHandler = new ExponentialRetry
            {
                MaxAttempts = MaxRetries
            };

            bool success = await RetryHandler.RunAsync(async attempt =>
            {
                try
                {
                    using (Stream localFileStream = File.OpenRead(localPackageFullPath))
                        using (HttpResponseMessage response = await client.GetAsync(packageContentUrl))
                        {
                            response.EnsureSuccessStatusCode();

                            // Check the headers for content length and md5
                            bool md5HeaderAvailable    = response.Headers.TryGetValues("Content-MD5", out var md5);
                            bool lengthHeaderAvailable = response.Headers.TryGetValues("Content-Length", out var contentLength);

                            if (lengthHeaderAvailable && long.Parse(contentLength.Single()) != localFileStream.Length)
                            {
                                log.LogMessage(MessageImportance.Low, $"Package '{localPackageFullPath}' has different length than remote package '{packageContentUrl}'.");
                                result = PackageFeedStatus.ExistsAndDifferent;
                                return(true);
                            }

                            if (md5HeaderAvailable)
                            {
                                var localMD5 = AzureStorageUtils.CalculateMD5(localPackageFullPath);
                                if (!localMD5.Equals(md5.Single(), StringComparison.OrdinalIgnoreCase))
                                {
                                    log.LogMessage(MessageImportance.Low, $"Package '{localPackageFullPath}' has different MD5 hash than remote package '{packageContentUrl}'.");
                                }

                                result = PackageFeedStatus.ExistsAndDifferent;
                                return(true);
                            }

                            const int BufferSize = 64 * 1024;

                            // Otherwise, compare the streams
                            var remoteStream = await response.Content.ReadAsStreamAsync();
                            var streamsMatch = await GeneralUtils.CompareStreamsAsync(localFileStream, remoteStream, BufferSize);
                            result           = streamsMatch ? PackageFeedStatus.ExistsAndIdenticalToLocal : PackageFeedStatus.ExistsAndDifferent;
                            return(true);
                        }
                }
                // String based comparison because the status code isn't exposed in HttpRequestException
                // see here: https://github.com/dotnet/runtime/issues/23648
                catch (HttpRequestException e)
                {
                    if (e.Message.Contains("404 (Not Found)"))
                    {
                        result = PackageFeedStatus.DoesNotExist;
                        return(true);
                    }

                    // Retry this. Could be an http client timeout, 500, etc.
                    return(false);
                }
            });

            return(result);
        }
Esempio n. 30
0
        private async Task <bool> ExecuteAsync()
        {
            try
            {
                string accessId          = IsInternal ? "int" : "pub";
                string baseFeedName      = $"darc-{accessId}-{RepositoryName}-{CommitSha}";
                string versionedFeedName = baseFeedName;
                bool   needsUniqueName   = false;
                int    subVersion        = 0;
                var    containerName     = string.Empty;

                Log.LogMessage(MessageImportance.High, $"Creating a new Azure Storage internal feed ...");

                Match m = Regex.Match(AzureStorageFeedsBaseUrl, baseUrlRegex);
                if (m.Success)
                {
                    containerName = m.Groups["containername"].Value;
                }
                else
                {
                    Log.LogError($"Could not parse {nameof(AzureStorageFeedsBaseUrl)} to extract the container name: '{AzureStorageFeedsBaseUrl}'");
                    return(false);
                }

                AzureStorageUtils azUtils = new AzureStorageUtils(AzureStorageAccountName, AzureStorageAccountKey, containerName);

                // Create container if it doesn't already exist
                if (!await azUtils.CheckIfContainerExistsAsync())
                {
                    BlobContainerPermissions permissions = new BlobContainerPermissions
                    {
                        PublicAccess = IsInternal ? BlobContainerPublicAccessType.Off : BlobContainerPublicAccessType.Container
                    };

                    await azUtils.CreateContainerAsync(permissions);
                }

                // Create folder inside the container. Note that AzureStorage requires a folder
                // to have at least one file.
                do
                {
                    if (await azUtils.CheckIfBlobExistsAsync($"{versionedFeedName}/index.json"))
                    {
                        versionedFeedName = $"{baseFeedName}-{++subVersion}";
                        needsUniqueName   = true;
                    }
                    else
                    {
                        baseFeedName    = versionedFeedName;
                        needsUniqueName = false;
                    }
                } while (needsUniqueName);

                // Initialize the feed using sleet
                SleetSource sleetSource = new SleetSource()
                {
                    Name             = baseFeedName,
                    Type             = "azure",
                    BaseUri          = $"{AzureStorageFeedsBaseUrl}{baseFeedName}",
                    AccountName      = AzureStorageAccountName,
                    Container        = containerName,
                    FeedSubPath      = $"{baseFeedName}",
                    ConnectionString = $"DefaultEndpointsProtocol=https;AccountName={AzureStorageAccountName};AccountKey={AzureStorageAccountKey};EndpointSuffix=core.windows.net"
                };

                BlobFeedAction bfAction = new BlobFeedAction(sleetSource, AzureStorageAccountKey, Log);
                await bfAction.InitAsync();

                TargetFeedURL = $"{AzureStorageFeedsBaseUrl}{baseFeedName}";

                Log.LogMessage(MessageImportance.High, $"Feed '{TargetFeedURL}' created successfully!");
            }
            catch (Exception e)
            {
                Log.LogErrorFromException(e, true);
            }

            return(!Log.HasLoggedErrors);
        }