Example #1
0
        protected internal override async Task <JobContinuation> Execute()
        {
            // Give an extra 10 minutes to execute
            await Extend(TimeSpan.FromMinutes(10));

            Start = DateTime.UtcNow;

            // Defaults:
            //  SourceServerName = Sql.Legacy Server Name
            //  SourceDatabaseName = Sql.Legacy DB Name
            //  TargetServerName = SourceServerName
            SourceServerName   = String.IsNullOrEmpty(SourceServerName) ? Utils.GetSqlServerName(Config.Sql.Legacy.DataSource) : SourceServerName;
            SourceDatabaseName = String.IsNullOrEmpty(SourceDatabaseName) ? Config.Sql.Legacy.InitialCatalog : SourceDatabaseName;
            TargetServerName   = String.IsNullOrEmpty(TargetServerName) ? SourceServerName : TargetServerName;

            TargetDatabaseName = String.IsNullOrEmpty(TargetDatabaseNamePrefix) ?
                                 TargetDatabaseName :
                                 (TargetDatabaseNamePrefix + "_" + DateTime.UtcNow.ToString("yyyyMMMdd_HHmm") + "Z").ToLowerInvariant();

            // Use our invocation ID to generate a unique name
            CopyName = "copytemp_" + Context.Invocation.Id.ToString("N");

            Log.BeginningDatabaseCopyProcess(SourceServerName, SourceDatabaseName, TargetServerName, TargetDatabaseName, CopyName);

            using (var sql = CloudContext.Clients.CreateSqlManagementClient(Azure.GetCredentials(throwIfMissing: true)))
            {
                // 1. Start the copy to a unique-named database

                Log.StartingCopy(SourceServerName, SourceDatabaseName, TargetServerName, CopyName);
                var response = await sql.DatabaseCopies.CreateAsync(
                    SourceServerName,
                    SourceDatabaseName,
                    new DatabaseCopyCreateParameters()
                {
                    PartnerDatabase = CopyName,
                    PartnerServer   = TargetServerName
                });

                // Would have thrown if it failed, so now start checking the status
                CopyOperationId = response.DatabaseCopy.Name;
                Log.StartedCopy(CopyOperationId);

                return(await Resume());
            }
        }
Example #2
0
        protected internal override async Task <JobContinuation> Resume()
        {
            // Give us another 10 minutes to execute
            await Extend(TimeSpan.FromMinutes(10));

            using (var sql = CloudContext.Clients.CreateSqlManagementClient(Azure.GetCredentials(throwIfMissing: true)))
            {
                try
                {
                    // 2. Check the status of the copy
                    Log.CheckingCopyStatus(CopyOperationId);
                    var ops = await sql.DatabaseOperations.ListByDatabaseAsync(TargetServerName, CopyName);

                    var op = ops.FirstOrDefault();
                    switch (op.StateId)
                    {
                    case 2:     // COMPLETED (http://msdn.microsoft.com/en-us/library/azure/dn720371.aspx)
                        Log.CopyCompleted();
                        await CompleteCopy(sql);

                        Log.CompletedDatabaseCopyProcess(SourceServerName, SourceDatabaseName, TargetServerName, TargetDatabaseName);
                        return(Complete());

                    case 3:     // FAILED
                        // Copy failed! Fail the whole job
                        throw new JobFailureException(op.Error);

                    default:
                        // Copy is still in progress, check for timeout
                        if (Timeout.HasValue && ((DateTime.UtcNow - Context.Invocation.QueuedAt.UtcDateTime) >= Timeout.Value))
                        {
                            // Abort the copy
                            await AbortCopy(sql);

                            throw new JobFailureException("Copy operation exceeded timeout and was aborted.");
                        }

                        // Save state and wait for another five minutes
                        Log.CopyInProgress(op.PercentComplete);
                        return(Suspend(TimeSpan.FromMinutes(5), new
                        {
                            SourceServerName,
                            SourceDatabaseName,
                            TargetServerName,
                            TargetDatabaseName,
                            CopyName,
                            CopyOperationId,
                            Timeout,
                            Start
                        }));
                    }
                }
                catch (Exception)
                {
                    // Abort the copy
                    AbortCopy(sql).Wait();

                    throw;
                }
            }
        }
Example #3
0
        protected internal override async Task <JobContinuation> Execute()
        {
            ServerName = String.IsNullOrEmpty(ServerName) ? Utils.GetSqlServerName(Config.Sql.Legacy.DataSource) : ServerName;

            // Capture the current time in case the date changes during invocation
            DateTimeOffset now = DateTimeOffset.UtcNow;

            // Resolve the connection if not specified explicitly
            Log.PreparingToClean(ServerName);

            // Connect to the master database
            using (var sql = CloudContext.Clients.CreateSqlManagementClient(Azure.GetCredentials(throwIfMissing: true)))
            {
                // Get online databases
                Log.GettingDatabaseList(ServerName);
                var dbs = (await sql.Databases.ListAsync(ServerName)).ToList();
                Log.GotDatabases(dbs.Count, ServerName);

                // Determine which of these are backups
                var backups = dbs
                              .Select(d => DatabaseBackup <Database> .Create(d))
                              .Where(b => b != null && String.Equals(NamePrefix, b.Prefix, StringComparison.OrdinalIgnoreCase))
                              .ToList();

                // Start collecting a list of backups we're going to keep
                var keepers = new HashSet <DatabaseBackup <Database> >();

                // Group backups by UTC Day
                var backupsByDate = backups
                                    .GroupBy(b => b.Timestamp.UtcDateTime.Date)
                                    .OrderByDescending(g => g.Key);

                // Keep the last backup from today and the max daily backups if any
                var dailyBackups = backupsByDate
                                   .Take(MaxDailyCopies ?? 1)
                                   .Select(g => g.OrderBy(db => db.Timestamp).Last());
                foreach (var keeper in dailyBackups)
                {
                    keepers.Add(keeper);
                }

                // Keep the most recent backups based on MaxRunningBackups
                foreach (var keeper in backups.OrderByDescending(b => b.Timestamp).Take(MaxRunningCopies ?? 1))
                {
                    keepers.Add(keeper);
                }

                // Report keepers
                foreach (var keeper in keepers)
                {
                    Log.KeepingBackup(keeper.Db.Name);
                }

                // Delete the others!
                foreach (var db in backups.Select(b => b.Db.Name).Except(keepers.Select(b => b.Db.Name), StringComparer.OrdinalIgnoreCase))
                {
                    Log.DeletingBackup(db);
                    if (!WhatIf)
                    {
                        await sql.Databases.DeleteAsync(ServerName, db);
                    }
                    Log.DeletedBackup(db);
                }

                // Clean out CopyTemp databases older than 3 hours
                var copytemps = dbs
                                .Where(db =>
                                       db.Name.StartsWith("copytemp", StringComparison.OrdinalIgnoreCase) &&
                                       db.CreationDate < DateTime.UtcNow.AddHours(-3));
                foreach (var copytemp in copytemps)
                {
                    Log.DeletingBackup(copytemp.Name);
                    if (!WhatIf)
                    {
                        await sql.Databases.DeleteAsync(ServerName, copytemp.Name);
                    }
                    Log.DeletedBackup(copytemp.Name);
                }
            }
            return(Complete());
        }