예제 #1
0
        private static ChangeResourceRecordSetsResponse SetARecord(AmazonRoute53Client route53Client, string publicIp, AppSettings appConfig)
        {
            var ret = route53Client.ChangeResourceRecordSetsAsync(new ChangeResourceRecordSetsRequest()
            {
                HostedZoneId = appConfig.HostedZoneId,
                ChangeBatch  = new ChangeBatch()
                {
                    Changes = new List <Change>()
                    {
                        new Change()
                        {
                            Action            = ChangeAction.UPSERT,
                            ResourceRecordSet = new ResourceRecordSet()
                            {
                                Name            = appConfig.RecordName,
                                Type            = appConfig.Type,
                                TTL             = appConfig.TTL,
                                ResourceRecords = new List <ResourceRecord>()
                                {
                                    new ResourceRecord()
                                    {
                                        Value = publicIp
                                    }
                                }
                            }
                        }
                    }
                }
            }).Result;

            return(ret);
        }
예제 #2
0
        public async Task <bool> UpdateIpAddressForSubdomain(string hostedZoneId, string fqdn, string newIpAddress)
        {
            using (AmazonRoute53Client route53Client = GetAmazonRoute53Client())
            {
                ListResourceRecordSetsResponse records = await route53Client.ListResourceRecordSetsAsync(new ListResourceRecordSetsRequest(hostedZoneId));

                // Look for an A record matching the FQDN that was passed in
                ResourceRecordSet matchingRecordSet = records?.ResourceRecordSets.FirstOrDefault(prop => prop.Name == fqdn && prop.Type == RRType.A);

                if (matchingRecordSet != null && matchingRecordSet.ResourceRecords.Any())
                {
                    if (matchingRecordSet.ResourceRecords.First().Value != newIpAddress)
                    {
                        matchingRecordSet.ResourceRecords.First().Value = newIpAddress;
                        ChangeBatch change = new ChangeBatch();
                        change.Changes.Add(new Change(ChangeAction.UPSERT, matchingRecordSet));

                        ChangeResourceRecordSetsResponse changeRequest = await route53Client.ChangeResourceRecordSetsAsync(new ChangeResourceRecordSetsRequest(hostedZoneId, change));

                        Log.Information("[Runtime = {StartTime}] Change request submitted to change subdomain {Subdomain} IP address to {IPAddress}.", Settings.StartTime, fqdn, newIpAddress);

                        return(changeRequest.HttpStatusCode == System.Net.HttpStatusCode.OK);
                    }
                    else
                    {
                        Log.Information("[Runtime = {StartTime}] Subdomain {Subdomain} found, but the IP address was already {IPAddress}.", Settings.StartTime, fqdn, newIpAddress);
                    }
                }

                return(false);
            }
        }
예제 #3
0
        /// <summary>
        /// Create or change a DNS record for a hosted zone.
        /// </summary>
        /// <param name="hostedZoneId">The ID of the hosted zone that contains the resource record sets that you want to change</param>
        /// <param name="name">The name of the DNS record set.</param>
        /// <param name="type">The type of the DNS record set.</param>
        /// <param name="value">The value of the record set.</param>
        /// <param name="ttl">The time to live of the record set.</param>
        /// <param name="settings">The <see cref="Route53Settings"/> required to upload to Amazon S3.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
        public async Task <string> CreateResourceRecordSet(string hostedZoneId, string name, RRType type, string value, long ttl, Route53Settings settings, CancellationToken cancellationToken = default(CancellationToken))
        {
            var recordSet = new ResourceRecordSet()
            {
                Name            = name,
                TTL             = ttl,
                Type            = type,
                ResourceRecords = new List <ResourceRecord>
                {
                    new ResourceRecord {
                        Value = value
                    }
                }
            };

            var change1 = new Change()
            {
                ResourceRecordSet = recordSet,
                Action            = ChangeAction.UPSERT
            };

            var changeBatch = new ChangeBatch()
            {
                Changes = new List <Change> {
                    change1
                }
            };

            var recordsetRequest = new ChangeResourceRecordSetsRequest()
            {
                HostedZoneId = hostedZoneId,
                ChangeBatch  = changeBatch
            };



            AmazonRoute53Client client = this.GetClient(settings);
            ChangeResourceRecordSetsResponse response = await client.ChangeResourceRecordSetsAsync(recordsetRequest);

            if (response.HttpStatusCode == HttpStatusCode.OK)
            {
                await this.WaitForChange(client, response.ChangeInfo.Id, 10000, 60);

                _Log.Verbose("Updated record set");
                return(response.ChangeInfo.Id);
            }
            else
            {
                _Log.Error("Could not change resource records");
                return("");
            }
        }
예제 #4
0
        public async Task CreateTxtRecordAsync(DnsZone zone, string relativeRecordName, IEnumerable <string> values)
        {
            var recordName = $"{relativeRecordName}.{zone.Name}.";

            var change = new Change
            {
                Action            = ChangeAction.CREATE,
                ResourceRecordSet = new ResourceRecordSet
                {
                    Name            = recordName,
                    Type            = RRType.TXT,
                    TTL             = 60,
                    ResourceRecords = values.Select(x => new ResourceRecord($"\"{x}\"")).ToList()
                }
            };

            var request = new ChangeResourceRecordSetsRequest(zone.Id, new ChangeBatch(new List <Change> {
                change
            }));

            await _amazonRoute53Client.ChangeResourceRecordSetsAsync(request);
        }
예제 #5
0
        private static void CreateDNSChangeAction(string domain, string hostName, string value, RRType type, ChangeAction action, int ttl)
        {
            string zoneId = FindHostedZoneID(domain);

            if (zoneId == null)
            {
                throw new Exception("Zone not found");
            }

            ResourceRecord resourceRecord = null;

            if (value != null)
            {
                resourceRecord = new ResourceRecord()
                {
                    Value = value
                };
            }

            var change = new Change
            {
                Action            = action,
                ResourceRecordSet = new ResourceRecordSet
                {
                    Name            = $"{hostName}.{domain}",
                    Type            = type,
                    TTL             = ttl,
                    ResourceRecords = resourceRecord != null ? new List <ResourceRecord>()
                    {
                        resourceRecord
                    } : null
                },
            };

            var changeBatch = new ChangeBatch();

            changeBatch.Changes.Add(change);
            var changeResourceRecordSetsRequest = new ChangeResourceRecordSetsRequest
            {
                ChangeBatch  = changeBatch,
                HostedZoneId = zoneId
            };

            var changeResourceResponse = c.ChangeResourceRecordSetsAsync(changeResourceRecordSetsRequest).Result;

            Console.WriteLine($"{changeResourceResponse.ChangeInfo.Status} {changeResourceResponse.ChangeInfo.Comment}");
        }
예제 #6
0
        private async Task <bool> ApplyDnsChange(HostedZone zone, ResourceRecordSet recordSet, ChangeAction action)
        {
            // prepare change
            var changeDetails = new Change()
            {
                ResourceRecordSet = recordSet,
                Action            = action
            };

            var changeBatch = new ChangeBatch()
            {
                Changes = new List <Change> {
                    changeDetails
                }
            };

            // Update the zone's resource record sets
            var recordsetRequest = new ChangeResourceRecordSetsRequest()
            {
                HostedZoneId = zone.Id,
                ChangeBatch  = changeBatch
            };

            _log?.Debug($"Route53 :: ApplyDnsChange : ChangeResourceRecordSetsAsync: {JsonConvert.SerializeObject(recordsetRequest.ChangeBatch)} ");

            var recordsetResponse = await _route53Client.ChangeResourceRecordSetsAsync(recordsetRequest);

            _log?.Debug($"Route53 :: ApplyDnsChange : ChangeResourceRecordSetsAsync Response: {JsonConvert.SerializeObject(recordsetResponse)} ");

            // Monitor the change status
            var changeRequest = new GetChangeRequest()
            {
                Id = recordsetResponse.ChangeInfo.Id
            };

            while (ChangeStatus.PENDING == (await _route53Client.GetChangeAsync(changeRequest)).ChangeInfo.Status)
            {
                System.Diagnostics.Debug.WriteLine("DNS change is pending.");
                await Task.Delay(1500);
            }

            _log?.Information("DNS change completed.");

            return(true);
        }
예제 #7
0
        private async static Task <bool> UpdateIpAddressForSubdomain(string hostedZoneId, string fqdn, string newIpAddress)
        {
            AmazonRoute53Config config = new AmazonRoute53Config()
            {
                RegionEndpoint = RegionEndpoint.GetBySystemName(Settings.AWSRegion) // TODO: inject
            };

            using (AmazonRoute53Client route53Client = new AmazonRoute53Client(Settings.AWSAccessKeyId, Settings.AWSAccessKeySecret, config))
            {
                ListResourceRecordSetsResponse records = await route53Client.ListResourceRecordSetsAsync(new ListResourceRecordSetsRequest(hostedZoneId));

                ResourceRecordSet matchingRecordSet = records?.ResourceRecordSets.FirstOrDefault(prop => prop.Name == fqdn && prop.Type == RRType.A);

                if (matchingRecordSet != null && matchingRecordSet.ResourceRecords.FirstOrDefault() != null)
                {
                    if (matchingRecordSet.ResourceRecords.FirstOrDefault().Value != newIpAddress)
                    {
                        matchingRecordSet.ResourceRecords.FirstOrDefault().Value = newIpAddress;
                        ChangeBatch change = new ChangeBatch();
                        change.Changes.Add(new Change(ChangeAction.UPSERT, matchingRecordSet));

                        ChangeResourceRecordSetsResponse changeRequest = await route53Client.ChangeResourceRecordSetsAsync(new ChangeResourceRecordSetsRequest(hostedZoneId, change));

                        Log.Information("[Runtime = {StartTime}] Change request submitted to change subdomain {Subdomain} IP address to {IPAddress}.", startTime, fqdn, newIpAddress);

                        return(changeRequest.HttpStatusCode == System.Net.HttpStatusCode.OK);
                    }
                    else
                    {
                        Log.Information("[Runtime = {StartTime}] Subdomain {Subdomain} found, but the IP address was already {IPAddress}.", startTime, fqdn, newIpAddress);
                    }
                }
                else
                {
                    // New subdomain
                    Log.Information("[Runtime = {StartTime}] Subdomain {Subdomain} record not found.", startTime, fqdn);
                }

                return(false);
            }
        }
예제 #8
0
        public async Task <ChangeResourceRecordSetsResponse> ChangeResourceRecordSetsAsync(string zoneId, ResourceRecordSet resourceRecordSet, Change change)
        {
            var sw       = Stopwatch.StartNew();
            int _timeout = 5 * 60 * 10000;
            PriorRequestNotCompleteException exception = null;

            do
            {
                try
                {
                    return(await _stopWatch.TimeLock(_rateLimit, _locker, async() =>
                    {
                        return await _client.ChangeResourceRecordSetsAsync(
                            new ChangeResourceRecordSetsRequest()
                        {
                            ChangeBatch = new ChangeBatch()
                            {
                                Changes = new List <Change>()
                                {
                                    change
                                }
                            },
                            HostedZoneId = zoneId
                        }).EnsureSuccessAsync();
                    }));
                }
                catch (PriorRequestNotCompleteException ex) //requires client reconnection
                {
                    exception = ex;
                    await Task.Delay(5000);

                    _locker.Lock(() =>
                    {
                        Initialize();
                    });
                }
            } while (sw.ElapsedMilliseconds < _timeout);

            throw exception;
        }
예제 #9
0
        public async Task <string> UpdateHostZoneRecordSetValue(string action, List <KeyValuePair <string, string> > recordsetChanges)
        {
            List <Change> changes = new List <Change>();

            foreach (var recordsetChange in recordsetChanges)
            {
                changes.Add(
                    new Change(
                        new ChangeAction(action),  //"UPSERT"
                        new ResourceRecordSet()
                {
                    Name            = recordsetChange.Key,
                    TTL             = 900,
                    Type            = RRType.CNAME,
                    ResourceRecords = new List <ResourceRecord>()
                    {
                        new ResourceRecord()
                        {
                            Value = recordsetChange.Value
                        }
                    }
                }
                        )
                    );
            }
            ;
            ChangeBatch batch   = new ChangeBatch(changes);
            var         request = new ChangeResourceRecordSetsRequest()
            {
                HostedZoneId = await GetHostZoneId(),
                ChangeBatch  = batch
            };
            var response = await client.ChangeResourceRecordSetsAsync(request);

            return(response.HttpStatusCode.ToString());
        }
        public void SaveClients()
        {
            //Output
            Output($"MCS: Starting Save Clients");

            string dataText = "";

            //Validate
            if (Clients == null || !Clients.Any())
            {
                //Output
                Output($"MCS: Had no Clients.");

                //Will update with an empty string - no clients
            }
            else
            {
                //Output
                Output($"MCS: Found {Clients.Count} Clients.");

                //1) Serialize to JSON text
                dataText = JsonConvert.SerializeObject(Clients);

                //2) Prepare the string (encrypt, compress)
                //Encrypt and Compress
                dataText = dataText.CompressThenEncrypt(Config.MultiClientSettings.Route53.EncryptionPassword);
            }

            //Add quotation marks
            dataText = "\"" + dataText + "\"";

            //3) Update to R53
            //New the Route 53 Client
            AmazonRoute53Client r53Client =
                new AmazonRoute53Client(
                    Config.BaseSettings.AWSAccessKeyID,
                    Config.BaseSettings.AWSSecretAccessKey,
                    new AmazonRoute53Config
            {
                RegionEndpoint = RegionEndpoint
            });

            //New the Change Record to push
            Change change =
                new Change
            {
                Action            = ChangeAction.UPSERT, //Insert or Update
                ResourceRecordSet =
                    new ResourceRecordSet
                {
                    Name            = Config.MultiClientSettings.Route53.Name,
                    TTL             = 300,
                    Type            = RRType.TXT,
                    ResourceRecords = new List <ResourceRecord> {
                        new ResourceRecord(dataText)
                    }
                }
            };

            //New the Change Request
            ChangeResourceRecordSetsRequest recordSetsRequest =
                new ChangeResourceRecordSetsRequest
            {
                HostedZoneId = Config.MultiClientSettings.Route53.R53ZoneId,
                ChangeBatch  = new ChangeBatch(new List <Change> {
                    change
                })
            };

            //Submitting the Change Request to the API and receiving back the ID
            ChangeResourceRecordSetsResponse recordSetResponse =
                r53Client
                .ChangeResourceRecordSetsAsync(recordSetsRequest)
                .GetAwaiter()
                .GetResult();

            //The ID of the response
            string changeId = recordSetResponse.ChangeInfo.Id;

            //Output
            Output($"MCS-R53: Change ID \"{changeId}\": ChangeRequest was submitted.");

            //Enquire with R53 the status of the change (R53 updates can be VERY slow business)
            GetChangeRequest changeRequest =
                new GetChangeRequest
            {
                Id = changeId
            };

            while (r53Client.GetChangeAsync(changeRequest).GetAwaiter().GetResult().ChangeInfo.Status == ChangeStatus.PENDING)
            {
                //Output
                Output($"MCS-R53: Change ID \"{changeId}\": Change is still pending. (Can take a while.)");

                //Wait
                Thread.Sleep(10 * 1000); //Wait ten seconds
            }

            //Output DONE
            Output($"MCS-R53: Change ID \"{changeId}\": Change IN SYNC. Done.");
            Output($"MCS: Completed Save of {Clients.Count} Clients");
        }
        /// <summary>
        /// Run a single item
        /// </summary>
        /// <param name="item">The item to run</param>
        public void RunItem(Route53Host item)
        {
            //Output
            Output($"R53: Starting item: {item}, new IP address: {IpState.NewIP}");

            //New the Route 53 Client
            AmazonRoute53Client r53Client =
                new AmazonRoute53Client(
                    Config.BaseSettings.AWSAccessKeyID,
                    Config.BaseSettings.AWSSecretAccessKey,
                    new AmazonRoute53Config {
                RegionEndpoint = RegionEndpoint
            });

            //New the Change Record to push
            Change change =
                new Change
            {
                Action            = ChangeAction.UPSERT, //Insert or Update
                ResourceRecordSet =
                    new ResourceRecordSet
                {
                    Name            = item.Name,
                    TTL             = item.TTL,
                    Type            = RRType.A,
                    ResourceRecords = new List <ResourceRecord> {
                        new ResourceRecord(IpState.NewIP)
                    }
                }
            };

            //New the Change Request
            ChangeResourceRecordSetsRequest recordSetsRequest =
                new ChangeResourceRecordSetsRequest
            {
                HostedZoneId = item.ZoneId,
                ChangeBatch  = new ChangeBatch(new List <Change> {
                    change
                })
            };

            //Submitting the Change Request to the API and receiving back the ID
            ChangeResourceRecordSetsResponse recordSetResponse = r53Client.ChangeResourceRecordSetsAsync(recordSetsRequest).GetAwaiter().GetResult();

            //The ID of the response
            string changeId = recordSetResponse.ChangeInfo.Id;

            //Output
            Output($"R53: Change ID \"{changeId}\": ChangeRequest was submitted.");

            //Enquire with R53 the status of the change (R53 updates can be VERY slow business)
            GetChangeRequest changeRequest =
                new GetChangeRequest
            {
                Id = changeId
            };

            while (r53Client.GetChangeAsync(changeRequest).GetAwaiter().GetResult().ChangeInfo.Status == ChangeStatus.PENDING)
            {
                //Output
                Output($"R53: Change ID \"{changeId}\": Change is still pending. (Can take a while.)");

                //Wait
                Thread.Sleep(10 * 1000); //Wait ten seconds
            }

            //Output DONE
            Output($"R53: Change ID \"{changeId}\": Change IN SYNC. Done.");
        }
        /// <summary>
        /// This method does all of the work to update the DNS records with our current WAN IP. This is separated from the main
        /// method to make it easier in the future to perform batch updates (if needed).
        /// </summary>
        /// <param name="id">The AWS Access key ID</param>
        /// <param name="secret">The AWS Access key secret</param>
        /// <param name="domain">The domain name we are going to be updating records for (e.g. shawnlehner.com)</param>
        /// <param name="subdomain">The subdomain we would like to update (e.g. "house" if we were updating house.shawnlehner.com)</param>
        private static async Task PerformDnsUpdate(string id, string secret, string domain, string subdomain)
        {
            #region Lookup Current WAN IP

            // We use ipify.org to quickly/easily get our external WAN IP address which we can later use
            // for updating our DNS records.

            string ip = null;

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://api.ipify.org");
            using (Stream s = (await request.GetResponseAsync()).GetResponseStream())
                using (StreamReader r = new StreamReader(s))
                {
                    ip = r.ReadToEnd();
                }

            #endregion

            // Combine our domain and subdomain to get the full record name
            string recordName = subdomain.Trim('.') + "." + domain.Trim('.');

            // Create our AWS API client for sending requests to the Route53 API
            AmazonRoute53Client client = new AmazonRoute53Client(id, secret, RegionEndpoint.USEast1);

            #region Lookup current state of the domain on Route53

            // Lookup the zone for our domain
            HostedZone zone = (await client.ListHostedZonesByNameAsync(new ListHostedZonesByNameRequest
            {
                DNSName = domain
            })).HostedZones.First();

            // Lookup our current records to see if we need to make an update
            ListResourceRecordSetsResponse recordSet = await client.ListResourceRecordSetsAsync(new ListResourceRecordSetsRequest
            {
                HostedZoneId    = zone.Id,
                MaxItems        = "1",
                StartRecordName = recordName
            });

            #endregion

            // Check to see if our IP is already up to date. No sense making a change if we don't need to.
            if (recordSet.ResourceRecordSets.Count > 0 &&
                recordSet.ResourceRecordSets[0].Name.Trim('.') == recordName &&
                recordSet.ResourceRecordSets[0].ResourceRecords[0].Value == ip)
            {
                return;
            }

            #region Request DNS record update with new IP

            // Our IP address is not up-to-date so we need to make a change request. We use UPSERT action which
            // will work whether or not a record already exists.
            ChangeResourceRecordSetsRequest changeRequest = new ChangeResourceRecordSetsRequest
            {
                HostedZoneId = zone.Id,
                ChangeBatch  = new ChangeBatch
                {
                    Changes = new List <Change>
                    {
                        new Change
                        {
                            ResourceRecordSet = new ResourceRecordSet
                            {
                                Name            = recordName,
                                TTL             = 60,
                                Type            = RRType.A,
                                ResourceRecords = new List <ResourceRecord> {
                                    new ResourceRecord {
                                        Value = ip
                                    }
                                }
                            },
                            Action = ChangeAction.UPSERT
                        }
                    }
                }
            };

            // Send our change request to the API
            ChangeResourceRecordSetsResponse response =
                await client.ChangeResourceRecordSetsAsync(changeRequest);

            // Check our response code to verify everything worked
            if (response.HttpStatusCode != HttpStatusCode.OK)
            {
                throw new Exception("API request to update DNS record has failed.");
            }

            #endregion
        }
        /// <summary>
        /// Used to modify recordset with value from api gateway code deploy in another account.
        /// </summary>
        /// <param name="jobEvent">CodePipeline event.</param>
        /// <param name="context">Lambda Context</param>
        /// <returns>Job success of the Lambda</returns>
        public async Task <AmazonWebServiceResponse> UpdateApiGatewayAliasRecordSet(CodePipelineJobEvent jobEvent, ILambdaContext context)
        {
            var jobId = jobEvent.CodePipelineJob.Id;

            context.Logger.LogLine($"JobId: {jobId}");

            using (var codePipelineClient = new AmazonCodePipelineClient())
                using (var s3Client = new AmazonS3Client())
                    using (var dnsClient = new AmazonRoute53Client())
                    {
                        // Prep the user parameters
                        var userParameters = jobEvent.CodePipelineJob.Data.ActionConfiguration.Configuration["UserParameters"];
                        context.Logger.LogLine("UserParameters:");
                        context.Logger.LogLine(userParameters);
                        var paramDict = JsonConvert.DeserializeObject <Dictionary <string, string> >(userParameters);

                        try
                        {
                            DnsSettings dnsSettings = null;

                            // Get the first (only) input artifact
                            var artifact           = jobEvent.CodePipelineJob.Data.InputArtifacts.First();
                            var artifactBucketName = artifact.Location.S3Location.BucketName;
                            var artifactBucketKey  = artifact.Location.S3Location.ObjectKey;

                            // Unzip and get json
                            using (var getResponse = await s3Client.GetObjectAsync(artifactBucketName, artifactBucketKey))
                            {
                                var memoryStream = new MemoryStream();
                                using (var objectStream = getResponse.ResponseStream)
                                {
                                    objectStream.CopyTo(memoryStream);
                                }


                                var searchFile = paramDict["DnsJson"];
                                context.Logger.LogLine("Unziping artifact");
                                context.Logger.LogLine($"Searching for {searchFile}");
                                using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Read))
                                {
                                    foreach (var entry in archive.Entries)
                                    {
                                        var fileName = entry.Name;
                                        context.Logger.LogLine("Checking File: " + entry.Name);

                                        if (searchFile == fileName)
                                        {
                                            using (var fileStream = entry.Open())
                                                using (var streamReader = new StreamReader(fileStream))
                                                {
                                                    var dnsJson = await streamReader.ReadToEndAsync();

                                                    dnsSettings = JsonConvert.DeserializeObject <DnsSettings>(dnsJson);
                                                }

                                            break;
                                        }
                                    }
                                }
                            }

                            // Get the hosted zones in the tools region
                            context.Logger.LogLine($"Searching for {dnsSettings.HostedZoneLookupDomainName}");
                            var hostedZones = await dnsClient.ListHostedZonesAsync();

                            var myHostedZone = hostedZones.HostedZones.FirstOrDefault(z => z.Name == dnsSettings.HostedZoneLookupDomainName);
                            if (myHostedZone == null)
                            {
                                var noZoneMessage = $"Hosted Zone {dnsSettings.HostedZoneLookupDomainName} could not be found";
                                context.Logger.LogLine(noZoneMessage);
                                var failureDetails = new FailureDetails
                                {
                                    Message = noZoneMessage,
                                    Type    = FailureType.ConfigurationError
                                };
                                return(await codePipelineClient.PutJobFailureResultAsync(jobId, failureDetails));
                            }

                            // The record set we need to create
                            var recordSet = new ResourceRecordSet
                            {
                                Name            = dnsSettings.WebApiDnsDomain,
                                Type            = RRType.A,
                                ResourceRecords = new List <ResourceRecord> {
                                    new ResourceRecord {
                                        Value = $"ALIAS {dnsSettings.RegionalDomainName}"
                                    }
                                }
                            };
                            var rsChange = new Change
                            {
                                Action            = ChangeAction.UPSERT,
                                ResourceRecordSet = recordSet
                            };
                            var rsChangeBatch = new ChangeBatch
                            {
                                Changes = new List <Change> {
                                    rsChange
                                }
                            };


                            // Create/Update the recordset
                            var changeDnsRequest = new ChangeResourceRecordSetsRequest
                            {
                                ChangeBatch  = rsChangeBatch,
                                HostedZoneId = myHostedZone.Id
                            };
                            var changeResponse = await dnsClient.ChangeResourceRecordSetsAsync(changeDnsRequest);

                            // Log and send the success response
                            context.Logger.LogLine($"Request Id {changeResponse.ChangeInfo.Id} submitted");
                            context.Logger.LogLine($"{dnsSettings.WebApiDnsDomain} => A ALIAS {dnsSettings.RegionalDomainName}");
                            var successResultRequest = new PutJobSuccessResultRequest
                            {
                                JobId = jobId
                            };
                            return(await codePipelineClient.PutJobSuccessResultAsync(successResultRequest));
                        }
                        catch (Exception ex)
                        {
                            // Send the failure response and log
                            return(await DoException(codePipelineClient, ex, jobId, context));
                        }
                    }
        }