• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *       http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.cloud.dns;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static com.google.common.collect.Lists.transform;
21 
22 import com.google.api.client.util.Data;
23 import com.google.api.services.dns.model.DnsKeySpec;
24 import com.google.api.services.dns.model.ManagedZone;
25 import com.google.api.services.dns.model.ManagedZoneDnsSecConfig;
26 import com.google.common.base.Function;
27 import com.google.common.base.MoreObjects;
28 import com.google.common.collect.ImmutableList;
29 import com.google.common.collect.ImmutableSet;
30 import com.google.common.collect.Lists;
31 import com.google.common.collect.Maps;
32 import java.io.Serializable;
33 import java.math.BigInteger;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Objects;
37 import java.util.Set;
38 import org.threeten.bp.Instant;
39 import org.threeten.bp.ZoneOffset;
40 import org.threeten.bp.format.DateTimeFormatter;
41 
42 /**
43  * A {@code Zone} represents a DNS zone hosted by the Google Cloud DNS service. A zone is a subtree
44  * of the DNS namespace under one administrative responsibility. See <a
45  * href="https://cloud.google.com/dns/api/v1/managedZones">Google Cloud DNS documentation</a> for
46  * more information.
47  */
48 public class ZoneInfo implements Serializable {
49 
50   private static final long serialVersionUID = -5313169712036079818L;
51   private static final DateTimeFormatter DATE_TIME_FORMATTER =
52       DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneOffset.UTC);
53 
54   private final String name;
55   private final String generatedId;
56   private final Long creationTimeMillis;
57   private final String dnsName;
58   private final String description;
59   private final String nameServerSet;
60   private final List<String> nameServers;
61   private final DnsSecConfig dnsSecConfig;
62   private final Map<String, String> labels;
63 
64   /** This class represents the DNS key spec. */
65   public static class KeySpec {
66 
67     private String algorithm;
68     private Long keyLength;
69     private String keyType;
70 
71     public static class Builder {
72       private String algorithm;
73       private Long keyLength;
74       private String keyType;
75 
Builder()76       private Builder() {}
77 
Builder(KeySpec keySpec)78       private Builder(KeySpec keySpec) {
79         this.algorithm = keySpec.algorithm;
80         this.keyLength = keySpec.keyLength;
81         this.keyType = keySpec.getKeyType();
82       }
83 
84       /** Specifies the DNSSEC algorithm of this key. */
setAlgorithm(String algorithm)85       public Builder setAlgorithm(String algorithm) {
86         this.algorithm = algorithm;
87         return this;
88       }
89 
90       /** Specifies the length of the keys in bits. */
setKeyLength(Long keyLength)91       public Builder setKeyLength(Long keyLength) {
92         this.keyLength = keyLength;
93         return this;
94       }
95 
96       /**
97        * Specifies the key type, Whether this key is a signing key (KSK) or a zone signing key
98        * (ZSK).
99        */
setKeyType(String keyType)100       public Builder setKeyType(String keyType) {
101         this.keyType = keyType;
102         return this;
103       }
104 
105       /** Creates a {@code KeySpec} object. */
build()106       public KeySpec build() {
107         return new KeySpec(this);
108       }
109     }
110 
111     /** Returns a builder for {@code KeySpec} objects. */
newBuilder()112     public static Builder newBuilder() {
113       return new Builder();
114     }
115 
KeySpec(Builder builder)116     private KeySpec(Builder builder) {
117       algorithm = builder.algorithm;
118       keyLength = builder.keyLength;
119       keyType = builder.keyType;
120     }
121 
122     @Override
equals(Object o)123     public boolean equals(Object o) {
124       if (this == o) {
125         return true;
126       }
127       if (o == null || getClass() != o.getClass()) {
128         return false;
129       }
130       KeySpec keySpec = (KeySpec) o;
131       return Objects.equals(algorithm, keySpec.algorithm)
132           && Objects.equals(keyLength, keySpec.keyLength)
133           && Objects.equals(keyType, keySpec.keyType);
134     }
135 
136     @Override
toString()137     public String toString() {
138       return MoreObjects.toStringHelper(this)
139           .add("algorithm", getAlgorithm())
140           .add("keyLength", getKeyLength())
141           .add("keyType", getKeyType())
142           .toString();
143     }
144 
145     @Override
hashCode()146     public int hashCode() {
147       return Objects.hash(algorithm, keyLength, keyType);
148     }
149 
toPb()150     DnsKeySpec toPb() {
151       DnsKeySpec dnsKeySpecPb = new DnsKeySpec();
152       dnsKeySpecPb.setAlgorithm(algorithm);
153       dnsKeySpecPb.setKeyLength(keyLength);
154       dnsKeySpecPb.setKeyType(keyType);
155       return dnsKeySpecPb;
156     }
157 
fromPb(DnsKeySpec dnsKeySpec)158     static KeySpec fromPb(DnsKeySpec dnsKeySpec) {
159       Builder builder = newBuilder();
160       builder.setAlgorithm(dnsKeySpec.getAlgorithm() == null ? null : dnsKeySpec.getAlgorithm());
161       builder.setKeyLength(dnsKeySpec.getKeyLength() == null ? null : dnsKeySpec.getKeyLength());
162       builder.setKeyType(dnsKeySpec.getKeyType() == null ? null : dnsKeySpec.getKeyType());
163       return builder.build();
164     }
165 
166     /** Returns the DNSSEC algorithm of this key. */
getAlgorithm()167     public String getAlgorithm() {
168       return algorithm;
169     }
170 
171     /** Returns the key length. */
getKeyLength()172     public Long getKeyLength() {
173       return keyLength;
174     }
175 
176     /** Returns the key type. */
getKeyType()177     public String getKeyType() {
178       return keyType;
179     }
180   }
181 
182   /** This class represents the DNSSEC configuration. */
183   public static class DnsSecConfig {
184 
185     private static final Set<String> VALID_STATE_VALUES = ImmutableSet.of("on", "off", "transfer");
186     private static final Set<String> VALID_NONEXISTANCE_VALUES = ImmutableSet.of("nsec", "nsec3");
187 
188     private List<KeySpec> defaultKeySpecs;
189     private String nonExistence;
190     private String state;
191 
192     public static class Builder {
193       private List<KeySpec> defaultKeySpecs;
194       private String nonExistence;
195       private String state;
196 
Builder()197       private Builder() {}
198 
Builder(DnsSecConfig dnsSecConfig)199       private Builder(DnsSecConfig dnsSecConfig) {
200         this.defaultKeySpecs = dnsSecConfig.defaultKeySpecs;
201         this.nonExistence = dnsSecConfig.nonExistence;
202         this.state = dnsSecConfig.state;
203       }
204 
205       /**
206        * Specifies parameters for generating initial DnsKeys for this ManagedZone. This can be
207        * change while state is OFF.
208        */
setDefaultKeySpecs(List<KeySpec> defaultKeySpecs)209       public Builder setDefaultKeySpecs(List<KeySpec> defaultKeySpecs) {
210         this.defaultKeySpecs = defaultKeySpecs;
211         return this;
212       }
213 
214       /**
215        * Specifies the mechanism for authenticated denial-of-existence responses. This can be change
216        * while state is OFF. Acceptable values are 'nsec' or 'nsec3'.
217        *
218        * @throws IllegalArgumentException if nonExistence value is not acceptable
219        */
setNonExistence(String nonExistence)220       public Builder setNonExistence(String nonExistence) {
221         validateValue(nonExistence, VALID_NONEXISTANCE_VALUES);
222         this.nonExistence = nonExistence;
223         return this;
224       }
225 
226       /**
227        * Specifies whether DNSSEC is enabled, and what mode it is in. Acceptable values are 'on',
228        * 'off' or 'transfer'.
229        *
230        * @throws IllegalArgumentException if state value is not acceptable
231        */
setState(String state)232       public Builder setState(String state) {
233         validateValue(state, VALID_STATE_VALUES);
234         this.state = state;
235         return this;
236       }
237 
238       /** Creates a {@code DnsSecConfig} object. */
build()239       public DnsSecConfig build() {
240         return new DnsSecConfig(this);
241       }
242     }
243 
244     /** Returns a builder for the current blob. */
toBuilder()245     public Builder toBuilder() {
246       return new Builder(this);
247     }
248 
249     /** Returns a builder for {@code DnsSecConfig} objects. */
newBuilder()250     public static Builder newBuilder() {
251       return new Builder();
252     }
253 
DnsSecConfig(Builder builder)254     private DnsSecConfig(Builder builder) {
255       defaultKeySpecs = builder.defaultKeySpecs;
256       nonExistence = builder.nonExistence;
257       state = builder.state;
258     }
259 
260     @Override
equals(Object o)261     public boolean equals(Object o) {
262       if (this == o) {
263         return true;
264       }
265       if (o == null || getClass() != o.getClass()) {
266         return false;
267       }
268       DnsSecConfig that = (DnsSecConfig) o;
269       return Objects.equals(defaultKeySpecs, that.defaultKeySpecs)
270           && Objects.equals(nonExistence, that.nonExistence)
271           && Objects.equals(state, that.state);
272     }
273 
274     @Override
hashCode()275     public int hashCode() {
276       return Objects.hash(defaultKeySpecs, nonExistence, state);
277     }
278 
279     @Override
toString()280     public String toString() {
281       return MoreObjects.toStringHelper(this)
282           .add("defaultKeySpecs", getDefaultKeySpecs())
283           .add("nonExistence", getNonExistence())
284           .add("state", getState())
285           .toString();
286     }
287 
toPb()288     ManagedZoneDnsSecConfig toPb() {
289       ManagedZoneDnsSecConfig dnsSecConfigPb = new ManagedZoneDnsSecConfig();
290       if (defaultKeySpecs != null) {
291         dnsSecConfigPb.setDefaultKeySpecs(
292             transform(
293                 defaultKeySpecs,
294                 new Function<KeySpec, DnsKeySpec>() {
295                   @Override
296                   public DnsKeySpec apply(KeySpec keySpec) {
297                     return keySpec.toPb();
298                   }
299                 }));
300       }
301       dnsSecConfigPb.setNonExistence(nonExistence);
302       dnsSecConfigPb.setState(state);
303       return dnsSecConfigPb;
304     }
305 
fromPb(ManagedZoneDnsSecConfig managedZoneDnsSecConfig)306     static DnsSecConfig fromPb(ManagedZoneDnsSecConfig managedZoneDnsSecConfig) {
307       Builder builder = newBuilder();
308       if (managedZoneDnsSecConfig.getDefaultKeySpecs() != null) {
309         builder.setDefaultKeySpecs(
310             transform(
311                 managedZoneDnsSecConfig.getDefaultKeySpecs(),
312                 new Function<DnsKeySpec, KeySpec>() {
313                   @Override
314                   public KeySpec apply(DnsKeySpec dnsKeySpec) {
315                     return KeySpec.fromPb(dnsKeySpec);
316                   }
317                 }));
318       }
319       builder.setNonExistence(managedZoneDnsSecConfig.getNonExistence());
320       builder.setState(managedZoneDnsSecConfig.getState());
321       return builder.build();
322     }
323 
324     /** Returns the DefaultKeySpecs. */
getDefaultKeySpecs()325     public List<KeySpec> getDefaultKeySpecs() {
326       return defaultKeySpecs;
327     }
328 
329     /** Returns the authenticated denial-of-existence responses. */
getNonExistence()330     public String getNonExistence() {
331       return nonExistence;
332     }
333 
334     /** Returns the DNSSEC state. */
getState()335     public String getState() {
336       return state;
337     }
338 
validateValue(String value, Set<String> validValues)339     private static void validateValue(String value, Set<String> validValues) {
340       if (!validValues.contains(value)) {
341         throw new IllegalArgumentException(
342             "Invalid value, Use one of the value from acceptable values " + validValues);
343       }
344     }
345   }
346 
347   /** Builder for {@code ZoneInfo}. */
348   public abstract static class Builder {
349 
350     /** Sets a mandatory user-provided name for the zone. It must be unique within the project. */
setName(String name)351     public abstract Builder setName(String name);
352 
353     /** Sets service-generated id for the zone. */
setGeneratedId(String generatedId)354     abstract Builder setGeneratedId(String generatedId);
355 
356     /** Sets the time when this zone was created. */
setCreationTimeMillis(long creationTimeMillis)357     abstract Builder setCreationTimeMillis(long creationTimeMillis);
358 
359     /** Sets a mandatory DNS name of this zone, for instance "example.com.". */
setDnsName(String dnsName)360     public abstract Builder setDnsName(String dnsName);
361 
362     /**
363      * Sets a mandatory description for this zone. The value is a string of at most 1024 characters
364      * which has no effect on the zone's function.
365      */
setDescription(String description)366     public abstract Builder setDescription(String description);
367 
368     /**
369      * Optionally specifies the NameServerSet for this zone. A NameServerSet is a set of DNS name
370      * servers that all host the same zones. Most users will not need to specify this value.
371      */
setNameServerSet(String nameServerSet)372     abstract Builder setNameServerSet(String nameServerSet);
373     // this should not be included in tooling as per the service owners
374 
375     /**
376      * Sets a list of servers that hold the information about the zone. This information is provided
377      * by Google Cloud DNS and is read only.
378      */
setNameServers(List<String> nameServers)379     abstract Builder setNameServers(List<String> nameServers);
380 
381     /** Sets the DNSSEC configuration. */
setDnsSecConfig(DnsSecConfig dnsSecConfig)382     public Builder setDnsSecConfig(DnsSecConfig dnsSecConfig) {
383       return this;
384     }
385 
386     /** Sets the label of this zone. */
setLabels(Map<String, String> labels)387     public Builder setLabels(Map<String, String> labels) {
388       return this;
389     }
390 
391     /** Builds the instance of {@code ZoneInfo} based on the information set by this builder. */
build()392     public abstract ZoneInfo build();
393   }
394 
395   static class BuilderImpl extends Builder {
396     private String name;
397     private String generatedId;
398     private Long creationTimeMillis;
399     private String dnsName;
400     private String description;
401     private String nameServerSet;
402     private List<String> nameServers;
403     private DnsSecConfig dnsSecConfig;
404     private Map<String, String> labels;
405 
BuilderImpl(String name)406     private BuilderImpl(String name) {
407       this.name = checkNotNull(name);
408     }
409 
410     /** Creates a builder from an existing ZoneInfo object. */
BuilderImpl(ZoneInfo info)411     BuilderImpl(ZoneInfo info) {
412       this.name = info.name;
413       this.generatedId = info.generatedId;
414       this.creationTimeMillis = info.creationTimeMillis;
415       this.dnsName = info.dnsName;
416       this.description = info.description;
417       this.nameServerSet = info.nameServerSet;
418       if (info.nameServers != null) {
419         this.nameServers = ImmutableList.copyOf(info.nameServers);
420       }
421       this.dnsSecConfig = info.dnsSecConfig;
422       this.labels = info.labels;
423     }
424 
425     @Override
setName(String name)426     public Builder setName(String name) {
427       this.name = checkNotNull(name);
428       return this;
429     }
430 
431     @Override
setGeneratedId(String generatedId)432     Builder setGeneratedId(String generatedId) {
433       this.generatedId = generatedId;
434       return this;
435     }
436 
437     @Override
setCreationTimeMillis(long creationTimeMillis)438     Builder setCreationTimeMillis(long creationTimeMillis) {
439       this.creationTimeMillis = creationTimeMillis;
440       return this;
441     }
442 
443     @Override
setDnsName(String dnsName)444     public Builder setDnsName(String dnsName) {
445       this.dnsName = checkNotNull(dnsName);
446       return this;
447     }
448 
449     @Override
setDescription(String description)450     public Builder setDescription(String description) {
451       this.description = checkNotNull(description);
452       return this;
453     }
454 
455     @Override
setNameServerSet(String nameServerSet)456     Builder setNameServerSet(String nameServerSet) {
457       this.nameServerSet = checkNotNull(nameServerSet);
458       return this;
459     }
460 
461     @Override
setNameServers(List<String> nameServers)462     Builder setNameServers(List<String> nameServers) {
463       checkNotNull(nameServers);
464       this.nameServers = Lists.newLinkedList(nameServers);
465       return this;
466     }
467 
468     @Override
setDnsSecConfig(DnsSecConfig dnsSecConfig)469     public Builder setDnsSecConfig(DnsSecConfig dnsSecConfig) {
470       this.dnsSecConfig = checkNotNull(dnsSecConfig);
471       return this;
472     }
473 
474     @Override
setLabels(Map<String, String> labels)475     public Builder setLabels(Map<String, String> labels) {
476       if (labels != null) {
477         this.labels =
478             Maps.transformValues(
479                 labels,
480                 new Function<String, String>() {
481                   @Override
482                   public String apply(String input) {
483                     // replace null values with empty strings
484                     return input == null ? Data.<String>nullOf(String.class) : input;
485                   }
486                 });
487       }
488       return this;
489     }
490 
491     @Override
build()492     public ZoneInfo build() {
493       return new ZoneInfo(this);
494     }
495   }
496 
ZoneInfo(BuilderImpl builder)497   ZoneInfo(BuilderImpl builder) {
498     this.name = builder.name;
499     this.generatedId = builder.generatedId;
500     this.creationTimeMillis = builder.creationTimeMillis;
501     this.dnsName = builder.dnsName;
502     this.description = builder.description;
503     this.nameServerSet = builder.nameServerSet;
504     this.nameServers =
505         builder.nameServers == null ? null : ImmutableList.copyOf(builder.nameServers);
506     this.dnsSecConfig = builder.dnsSecConfig;
507     this.labels = builder.labels;
508   }
509 
510   /**
511    * Returns a ZoneInfo object with assigned {@code name}, {@code dnsName} and {@code description}.
512    */
of(String name, String dnsName, String description)513   public static ZoneInfo of(String name, String dnsName, String description) {
514     return new BuilderImpl(name).setDnsName(dnsName).setDescription(description).build();
515   }
516 
517   /** Returns a {@code ZoneInfo} builder where the DNS name is set to the provided name. */
newBuilder(String name)518   public static Builder newBuilder(String name) {
519     return new BuilderImpl(name);
520   }
521 
522   /** Returns the user-defined name of the zone. */
getName()523   public String getName() {
524     return name;
525   }
526 
527   /** Returns the service-generated id for this zone. */
getGeneratedId()528   public String getGeneratedId() {
529     return generatedId;
530   }
531 
532   /** Returns the time when this zone was created on the server. */
getCreationTimeMillis()533   public Long getCreationTimeMillis() {
534     return creationTimeMillis;
535   }
536 
537   /** Returns the DNS name of this zone, for instance "example.com.". */
getDnsName()538   public String getDnsName() {
539     return dnsName;
540   }
541 
542   /** Returns the description of this zone. */
getDescription()543   public String getDescription() {
544     return description;
545   }
546 
547   /**
548    * Returns the optionally specified set of DNS name servers that all host this zone. This value is
549    * set only for specific use cases and is left empty for vast majority of users.
550    */
getNameServerSet()551   public String getNameServerSet() {
552     return nameServerSet;
553   }
554 
555   /** Returns the labels for this zone. */
getLabels()556   public Map<String, String> getLabels() {
557     return labels;
558   }
559 
560   /**
561    * The nameservers that the zone should be delegated to. This is defined by the Google DNS cloud.
562    */
getNameServers()563   public List<String> getNameServers() {
564     return nameServers == null ? ImmutableList.<String>of() : nameServers;
565   }
566 
getDnsSecConfig()567   public DnsSecConfig getDnsSecConfig() {
568     return dnsSecConfig;
569   }
570 
571   /** Returns a builder for {@code ZoneInfo} prepopulated with the metadata of this zone. */
toBuilder()572   public Builder toBuilder() {
573     return new BuilderImpl(this);
574   }
575 
toPb()576   ManagedZone toPb() {
577     ManagedZone pb = new ManagedZone();
578     pb.setDescription(this.getDescription());
579     pb.setDnsName(this.getDnsName());
580     if (this.getGeneratedId() != null) {
581       pb.setId(new BigInteger(this.getGeneratedId()));
582     }
583     pb.setName(this.getName());
584     pb.setNameServers(this.nameServers); // do use real attribute value which may be null
585     pb.setNameServerSet(this.getNameServerSet());
586     if (this.getCreationTimeMillis() != null) {
587       pb.setCreationTime(
588           DATE_TIME_FORMATTER.format(Instant.ofEpochMilli(this.getCreationTimeMillis())));
589     }
590     if (this.dnsSecConfig != null) {
591       pb.setDnssecConfig(this.dnsSecConfig.toPb());
592     }
593     if (this.getLabels() != null) {
594       pb.setLabels(labels);
595     }
596     return pb;
597   }
598 
fromPb(ManagedZone pb)599   static ZoneInfo fromPb(ManagedZone pb) {
600     Builder builder = new BuilderImpl(pb.getName());
601     if (pb.getDescription() != null) {
602       builder.setDescription(pb.getDescription());
603     }
604     if (pb.getDnsName() != null) {
605       builder.setDnsName(pb.getDnsName());
606     }
607     if (pb.getId() != null) {
608       builder.setGeneratedId(pb.getId().toString());
609     }
610     if (pb.getNameServers() != null) {
611       builder.setNameServers(pb.getNameServers());
612     }
613     if (pb.getNameServerSet() != null) {
614       builder.setNameServerSet(pb.getNameServerSet());
615     }
616     if (pb.getCreationTime() != null) {
617       builder.setCreationTimeMillis(
618           DATE_TIME_FORMATTER.parse(pb.getCreationTime(), Instant.FROM).toEpochMilli());
619     }
620     if (pb.getDnssecConfig() != null) {
621       builder.setDnsSecConfig(DnsSecConfig.fromPb(pb.getDnssecConfig()));
622     }
623     if (pb.getLabels() != null) {
624       builder.setLabels(pb.getLabels());
625     }
626     return builder.build();
627   }
628 
629   @Override
equals(Object obj)630   public boolean equals(Object obj) {
631     return obj == this
632         || obj != null
633             && obj.getClass().equals(ZoneInfo.class)
634             && Objects.equals(toPb(), ((ZoneInfo) obj).toPb());
635   }
636 
637   @Override
hashCode()638   public int hashCode() {
639     return Objects.hash(
640         name,
641         generatedId,
642         creationTimeMillis,
643         dnsName,
644         description,
645         nameServerSet,
646         nameServers,
647         dnsSecConfig,
648         labels);
649   }
650 
651   @Override
toString()652   public String toString() {
653     return MoreObjects.toStringHelper(this)
654         .add("name", getName())
655         .add("generatedId", getGeneratedId())
656         .add("description", getDescription())
657         .add("dnsName", getDnsName())
658         .add("nameServerSet", getNameServerSet())
659         .add("nameServers", getNameServers())
660         .add("creationTimeMillis", getCreationTimeMillis())
661         .add("dnsSecConfig", getDnsSecConfig())
662         .add("labels", getLabels())
663         .toString();
664   }
665 }
666