diff --git a/bubble-server/src/main/java/bubble/cloud/dns/godaddy/GoDaddyDnsCleanerMain.java b/bubble-server/src/main/java/bubble/cloud/dns/godaddy/GoDaddyDnsCleanerMain.java index e12e1a02..ef45591d 100644 --- a/bubble-server/src/main/java/bubble/cloud/dns/godaddy/GoDaddyDnsCleanerMain.java +++ b/bubble-server/src/main/java/bubble/cloud/dns/godaddy/GoDaddyDnsCleanerMain.java @@ -16,7 +16,10 @@ import org.cobbzilla.util.io.FileUtil; import org.cobbzilla.util.main.BaseMain; import org.cobbzilla.util.network.NetworkUtil; -import java.util.*; +import java.util.HashSet; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.stream.Collectors; import static bubble.cloud.dns.godaddy.GoDaddyDnsConfig.GODADDY_BASE_URI; @@ -25,7 +28,7 @@ import static org.cobbzilla.util.daemon.ZillaRuntime.empty; import static org.cobbzilla.util.daemon.ZillaRuntime.shortError; import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; import static org.cobbzilla.util.http.HttpMethods.PUT; -import static org.cobbzilla.util.http.HttpSchemes.SCHEME_HTTP; +import static org.cobbzilla.util.http.HttpSchemes.SCHEME_HTTPS; import static org.cobbzilla.util.http.HttpUtil.url2string; import static org.cobbzilla.util.io.FileUtil.abs; import static org.cobbzilla.util.json.JsonUtil.json; @@ -91,6 +94,8 @@ public class GoDaddyDnsCleanerMain extends BaseMain { retain.addAll(opts.getAdditionalSages()); retain.addAll(opts.getRetainHosts()); + final Set cnameValuesToRetain = opts.getRetainMatchingCNAMEValues(); + final GoDaddyDnsDriver dns = new GoDaddyDnsDriver(); dns.setCredentials(opts.getCredentials()); @@ -103,13 +108,14 @@ public class GoDaddyDnsCleanerMain extends BaseMain { final Set retainRecords = new HashSet<>(); final GoDaddyDnsRecord[] dnsRecords = dns._listGoDaddyDnsRecords(url+"/"+type); for (GoDaddyDnsRecord rec : dnsRecords) { - final String host = rec.getName() + "." + domain; - if (retain.contains(host)) { + final String recordName = rec.getName(); + final String host = recordName + "." + domain; + if (shouldRetain(rec, host, retain, cnameValuesToRetain)) { retainRecords.add(rec); } else { if (opts.hasHttpCheckTimeout()) { try { - url2string(SCHEME_HTTP + host + "/", opts.getHttpCheckTimeoutMillis()); + url2string(SCHEME_HTTPS + host + "/", opts.getHttpCheckTimeoutMillis()); final String msg = "Host seems alive, not removing: " + host; log.warn(msg); out("WARN: " + msg); @@ -126,14 +132,18 @@ public class GoDaddyDnsCleanerMain extends BaseMain { } } - log.info("Removing "+type+" records:\n" + json(removed)); - final HttpRequestBean domainUpdate = dns.auth(url+"/"+type) - .setMethod(PUT) - .setHeader(CONTENT_TYPE, APPLICATION_JSON) - .setEntity(json(retainRecords)); - final HttpResponseBean response = HttpUtil.getResponse(domainUpdate); - if (!response.isOk()) { - log.error("Error updating "+type+" records for domain: " + domain + ": " + response); + if (removed.isEmpty()) { + log.info("No "+type+" records found to remove for domain "+domain); + } else { + log.info("Removing "+type+" records for domain "+domain+":\n" + json(removed)); + final HttpRequestBean domainUpdate = dns.auth(url + "/" + type) + .setMethod(PUT) + .setHeader(CONTENT_TYPE, APPLICATION_JSON) + .setEntity(json(retainRecords)); + final HttpResponseBean response = HttpUtil.getResponse(domainUpdate); + if (!response.isOk()) { + log.error("Error updating " + type + " records for domain: " + domain + ": " + response); + } } } } catch (Exception e) { @@ -142,4 +152,18 @@ public class GoDaddyDnsCleanerMain extends BaseMain { } } + private boolean shouldRetain(GoDaddyDnsRecord rec, + String host, + SortedSet retain, + Set cnameValuesToRetain) { + return rec.getName().equals("@") + || retain.contains(host) + || retain.contains(rec.getName()) + || (rec.getType() == DnsType.CNAME + && ( + retain.contains(rec.getData()) + || cnameValuesToRetain.stream().anyMatch(val -> rec.getData().contains(val))) + ); + } + } diff --git a/bubble-server/src/main/java/bubble/cloud/dns/godaddy/GoDaddyDnsCleanerOptions.java b/bubble-server/src/main/java/bubble/cloud/dns/godaddy/GoDaddyDnsCleanerOptions.java index 664d9444..487e1fac 100644 --- a/bubble-server/src/main/java/bubble/cloud/dns/godaddy/GoDaddyDnsCleanerOptions.java +++ b/bubble-server/src/main/java/bubble/cloud/dns/godaddy/GoDaddyDnsCleanerOptions.java @@ -8,6 +8,7 @@ import bubble.model.cloud.CloudCredentials; import lombok.Getter; import lombok.Setter; import org.cobbzilla.util.collection.NameAndValue; +import org.cobbzilla.util.io.FileUtil; import org.cobbzilla.util.main.BaseMainOptions; import org.kohsuke.args4j.Option; @@ -15,8 +16,10 @@ import java.io.File; import java.io.IOException; import java.util.Collections; import java.util.Set; +import java.util.stream.Collectors; import static java.util.concurrent.TimeUnit.SECONDS; +import static org.cobbzilla.util.daemon.ZillaRuntime.die; import static org.cobbzilla.util.daemon.ZillaRuntime.empty; import static org.cobbzilla.util.network.NetworkUtil.toHostSet; @@ -71,6 +74,26 @@ public class GoDaddyDnsCleanerOptions extends BaseMainOptions { return hasRetainHostsFile() ? toHostSet(retainHostsFile) : Collections.emptySet(); } + public static final String USAGE_RETAIN_MATCHING_CNAMES = "File containing values to match in CNAME records, one per line. CNAME records containing one of these values will be retained."; + public static final String OPT_RETAIN_MATCHING_CNAMES = "-C"; + public static final String LONGOPT_RETAIN_MATCHING_CNAMES = "--retain-matching-cnames"; + @Option(name=OPT_RETAIN_MATCHING_CNAMES, aliases=LONGOPT_RETAIN_MATCHING_CNAMES, usage=USAGE_RETAIN_MATCHING_CNAMES) + @Getter @Setter private File retainMatchingCNAMEsFile; + public boolean hasRetainMatchingCNAMEsFile () { return !empty(retainMatchingCNAMEsFile); } + public Set getRetainMatchingCNAMEValues () throws IOException { + return hasRetainMatchingCNAMEsFile() ? toSet(retainMatchingCNAMEsFile) : Collections.emptySet(); + } + + private Set toSet(File f) { + try { + return FileUtil.toStringList(f).stream() + .filter(line -> !line.trim().isEmpty()) + .collect(Collectors.toSet()); + } catch (Exception e) { + return die("toSet: "+e); + } + } + public static final String USAGE_HTTP_CHECK = "Timeout for HTTP check in seconds. Use zero to disable check. Default is "+DEFAULT_HTTP_CHECK_TIMEOUT_SECONDS+" seconds"; public static final String OPT_HTTP_CHECK = "-H"; public static final String LONGOPT_HTTP_CHECK = "--http-check-timeout";