1# Copyright (c) 2014 Amazon.com, Inc. or its affiliates.  All Rights Reserved
2#
3# Permission is hereby granted, free of charge, to any person obtaining a
4# copy of this software and associated documentation files (the
5# "Software"), to deal in the Software without restriction, including
6# without limitation the rights to use, copy, modify, merge, publish, dis-
7# tribute, sublicense, and/or sell copies of the Software, and to permit
8# persons to whom the Software is furnished to do so, subject to the fol-
9# lowing conditions:
10#
11# The above copyright notice and this permission notice shall be included
12# in all copies or substantial portions of the Software.
13#
14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20# IN THE SOFTWARE.
21#
22
23import boto
24from boto.compat import json
25from boto.connection import AWSQueryConnection
26from boto.regioninfo import RegionInfo
27from boto.exception import JSONResponseError
28from boto.route53.domains import exceptions
29
30
31class Route53DomainsConnection(AWSQueryConnection):
32    """
33
34    """
35    APIVersion = "2014-05-15"
36    DefaultRegionName = "us-east-1"
37    DefaultRegionEndpoint = "route53domains.us-east-1.amazonaws.com"
38    ServiceName = "Route53Domains"
39    TargetPrefix = "Route53Domains_v20140515"
40    ResponseError = JSONResponseError
41
42    _faults = {
43        "DuplicateRequest": exceptions.DuplicateRequest,
44        "DomainLimitExceeded": exceptions.DomainLimitExceeded,
45        "InvalidInput": exceptions.InvalidInput,
46        "OperationLimitExceeded": exceptions.OperationLimitExceeded,
47        "UnsupportedTLD": exceptions.UnsupportedTLD,
48        "TLDRulesViolation": exceptions.TLDRulesViolation,
49    }
50
51
52    def __init__(self, **kwargs):
53        region = kwargs.pop('region', None)
54        if not region:
55            region = RegionInfo(self, self.DefaultRegionName,
56                                self.DefaultRegionEndpoint)
57
58        if 'host' not in kwargs or kwargs['host'] is None:
59            kwargs['host'] = region.endpoint
60
61        super(Route53DomainsConnection, self).__init__(**kwargs)
62        self.region = region
63
64    def _required_auth_capability(self):
65        return ['hmac-v4']
66
67    def check_domain_availability(self, domain_name, idn_lang_code=None):
68        """
69        This operation checks the availability of one domain name. You
70        can access this API without authenticating. Note that if the
71        availability status of a domain is pending, you must submit
72        another request to determine the availability of the domain
73        name.
74
75        :type domain_name: string
76        :param domain_name: The name of a domain.
77        Type: String
78
79        Default: None
80
81        Constraints: The domain name can contain only the letters a through z,
82            the numbers 0 through 9, and hyphen (-). Internationalized Domain
83            Names are not supported.
84
85        Required: Yes
86
87        :type idn_lang_code: string
88        :param idn_lang_code: Reserved for future use.
89
90        """
91        params = {'DomainName': domain_name, }
92        if idn_lang_code is not None:
93            params['IdnLangCode'] = idn_lang_code
94        return self.make_request(action='CheckDomainAvailability',
95                                 body=json.dumps(params))
96
97    def disable_domain_transfer_lock(self, domain_name):
98        """
99        This operation removes the transfer lock on the domain
100        (specifically the `clientTransferProhibited` status) to allow
101        domain transfers. We recommend you refrain from performing
102        this action unless you intend to transfer the domain to a
103        different registrar. Successful submission returns an
104        operation ID that you can use to track the progress and
105        completion of the action. If the request is not completed
106        successfully, the domain registrant will be notified by email.
107
108        :type domain_name: string
109        :param domain_name: The name of a domain.
110        Type: String
111
112        Default: None
113
114        Constraints: The domain name can contain only the letters a through z,
115            the numbers 0 through 9, and hyphen (-). Internationalized Domain
116            Names are not supported.
117
118        Required: Yes
119
120        """
121        params = {'DomainName': domain_name, }
122        return self.make_request(action='DisableDomainTransferLock',
123                                 body=json.dumps(params))
124
125    def enable_domain_transfer_lock(self, domain_name):
126        """
127        This operation sets the transfer lock on the domain
128        (specifically the `clientTransferProhibited` status) to
129        prevent domain transfers. Successful submission returns an
130        operation ID that you can use to track the progress and
131        completion of the action. If the request is not completed
132        successfully, the domain registrant will be notified by email.
133
134        :type domain_name: string
135        :param domain_name: The name of a domain.
136        Type: String
137
138        Default: None
139
140        Constraints: The domain name can contain only the letters a through z,
141            the numbers 0 through 9, and hyphen (-). Internationalized Domain
142            Names are not supported.
143
144        Required: Yes
145
146        """
147        params = {'DomainName': domain_name, }
148        return self.make_request(action='EnableDomainTransferLock',
149                                 body=json.dumps(params))
150
151    def get_domain_detail(self, domain_name):
152        """
153        This operation returns detailed information about the domain.
154        The domain's contact information is also returned as part of
155        the output.
156
157        :type domain_name: string
158        :param domain_name: The name of a domain.
159        Type: String
160
161        Default: None
162
163        Constraints: The domain name can contain only the letters a through z,
164            the numbers 0 through 9, and hyphen (-). Internationalized Domain
165            Names are not supported.
166
167        Required: Yes
168
169        """
170        params = {'DomainName': domain_name, }
171        return self.make_request(action='GetDomainDetail',
172                                 body=json.dumps(params))
173
174    def get_operation_detail(self, operation_id):
175        """
176        This operation returns the current status of an operation that
177        is not completed.
178
179        :type operation_id: string
180        :param operation_id: The identifier for the operation for which you
181            want to get the status. Amazon Route 53 returned the identifier in
182            the response to the original request.
183        Type: String
184
185        Default: None
186
187        Required: Yes
188
189        """
190        params = {'OperationId': operation_id, }
191        return self.make_request(action='GetOperationDetail',
192                                 body=json.dumps(params))
193
194    def list_domains(self, marker=None, max_items=None):
195        """
196        This operation returns all the domain names registered with
197        Amazon Route 53 for the current AWS account.
198
199        :type marker: string
200        :param marker: For an initial request for a list of domains, omit this
201            element. If the number of domains that are associated with the
202            current AWS account is greater than the value that you specified
203            for `MaxItems`, you can use `Marker` to return additional domains.
204            Get the value of `NextPageMarker` from the previous response, and
205            submit another request that includes the value of `NextPageMarker`
206            in the `Marker` element.
207        Type: String
208
209        Default: None
210
211        Constraints: The marker must match the value specified in the previous
212            request.
213
214        Required: No
215
216        :type max_items: integer
217        :param max_items: Number of domains to be returned.
218        Type: Integer
219
220        Default: 20
221
222        Constraints: A numeral between 1 and 100.
223
224        Required: No
225
226        """
227        params = {}
228        if marker is not None:
229            params['Marker'] = marker
230        if max_items is not None:
231            params['MaxItems'] = max_items
232        return self.make_request(action='ListDomains',
233                                 body=json.dumps(params))
234
235    def list_operations(self, marker=None, max_items=None):
236        """
237        This operation returns the operation IDs of operations that
238        are not yet complete.
239
240        :type marker: string
241        :param marker: For an initial request for a list of operations, omit
242            this element. If the number of operations that are not yet complete
243            is greater than the value that you specified for `MaxItems`, you
244            can use `Marker` to return additional operations. Get the value of
245            `NextPageMarker` from the previous response, and submit another
246            request that includes the value of `NextPageMarker` in the `Marker`
247            element.
248        Type: String
249
250        Default: None
251
252        Required: No
253
254        :type max_items: integer
255        :param max_items: Number of domains to be returned.
256        Type: Integer
257
258        Default: 20
259
260        Constraints: A value between 1 and 100.
261
262        Required: No
263
264        """
265        params = {}
266        if marker is not None:
267            params['Marker'] = marker
268        if max_items is not None:
269            params['MaxItems'] = max_items
270        return self.make_request(action='ListOperations',
271                                 body=json.dumps(params))
272
273    def register_domain(self, domain_name, duration_in_years, admin_contact,
274                        registrant_contact, tech_contact, idn_lang_code=None,
275                        auto_renew=None, privacy_protect_admin_contact=None,
276                        privacy_protect_registrant_contact=None,
277                        privacy_protect_tech_contact=None):
278        """
279        This operation registers a domain. Domains are registered by
280        the AWS registrar partner, Gandi. For some top-level domains
281        (TLDs), this operation requires extra parameters.
282
283        When you register a domain, Amazon Route 53 does the
284        following:
285
286
287        + Creates a Amazon Route 53 hosted zone that has the same name
288          as the domain. Amazon Route 53 assigns four name servers to
289          your hosted zone and automatically updates your domain
290          registration with the names of these name servers.
291        + Enables autorenew, so your domain registration will renew
292          automatically each year. We'll notify you in advance of the
293          renewal date so you can choose whether to renew the
294          registration.
295        + Optionally enables privacy protection, so WHOIS queries
296          return contact information for our registrar partner, Gandi,
297          instead of the information you entered for registrant, admin,
298          and tech contacts.
299        + If registration is successful, returns an operation ID that
300          you can use to track the progress and completion of the
301          action. If the request is not completed successfully, the
302          domain registrant is notified by email.
303        + Charges your AWS account an amount based on the top-level
304          domain. For more information, see `Amazon Route 53 Pricing`_.
305
306        :type domain_name: string
307        :param domain_name: The name of a domain.
308        Type: String
309
310        Default: None
311
312        Constraints: The domain name can contain only the letters a through z,
313            the numbers 0 through 9, and hyphen (-). Internationalized Domain
314            Names are not supported.
315
316        Required: Yes
317
318        :type idn_lang_code: string
319        :param idn_lang_code: Reserved for future use.
320
321        :type duration_in_years: integer
322        :param duration_in_years: The number of years the domain will be
323            registered. Domains are registered for a minimum of one year. The
324            maximum period depends on the top-level domain.
325        Type: Integer
326
327        Default: 1
328
329        Valid values: Integer from 1 to 10
330
331        Required: Yes
332
333        :type auto_renew: boolean
334        :param auto_renew: Indicates whether the domain will be automatically
335            renewed ( `True`) or not ( `False`). Autorenewal only takes effect
336            after the account is charged.
337        Type: Boolean
338
339        Valid values: `True` | `False`
340
341        Default: `True`
342
343        Required: No
344
345        :type admin_contact: dict
346        :param admin_contact: Provides detailed contact information.
347        Type: Complex
348
349        Children: `FirstName`, `MiddleName`, `LastName`, `ContactType`,
350            `OrganizationName`, `AddressLine1`, `AddressLine2`, `City`,
351            `State`, `CountryCode`, `ZipCode`, `PhoneNumber`, `Email`, `Fax`,
352            `ExtraParams`
353
354        Required: Yes
355
356        :type registrant_contact: dict
357        :param registrant_contact: Provides detailed contact information.
358        Type: Complex
359
360        Children: `FirstName`, `MiddleName`, `LastName`, `ContactType`,
361            `OrganizationName`, `AddressLine1`, `AddressLine2`, `City`,
362            `State`, `CountryCode`, `ZipCode`, `PhoneNumber`, `Email`, `Fax`,
363            `ExtraParams`
364
365        Required: Yes
366
367        :type tech_contact: dict
368        :param tech_contact: Provides detailed contact information.
369        Type: Complex
370
371        Children: `FirstName`, `MiddleName`, `LastName`, `ContactType`,
372            `OrganizationName`, `AddressLine1`, `AddressLine2`, `City`,
373            `State`, `CountryCode`, `ZipCode`, `PhoneNumber`, `Email`, `Fax`,
374            `ExtraParams`
375
376        Required: Yes
377
378        :type privacy_protect_admin_contact: boolean
379        :param privacy_protect_admin_contact: Whether you want to conceal
380            contact information from WHOIS queries. If you specify true, WHOIS
381            ("who is") queries will return contact information for our
382            registrar partner, Gandi, instead of the contact information that
383            you enter.
384        Type: Boolean
385
386        Default: `True`
387
388        Valid values: `True` | `False`
389
390        Required: No
391
392        :type privacy_protect_registrant_contact: boolean
393        :param privacy_protect_registrant_contact: Whether you want to conceal
394            contact information from WHOIS queries. If you specify true, WHOIS
395            ("who is") queries will return contact information for our
396            registrar partner, Gandi, instead of the contact information that
397            you enter.
398        Type: Boolean
399
400        Default: `True`
401
402        Valid values: `True` | `False`
403
404        Required: No
405
406        :type privacy_protect_tech_contact: boolean
407        :param privacy_protect_tech_contact: Whether you want to conceal
408            contact information from WHOIS queries. If you specify true, WHOIS
409            ("who is") queries will return contact information for our
410            registrar partner, Gandi, instead of the contact information that
411            you enter.
412        Type: Boolean
413
414        Default: `True`
415
416        Valid values: `True` | `False`
417
418        Required: No
419
420        """
421        params = {
422            'DomainName': domain_name,
423            'DurationInYears': duration_in_years,
424            'AdminContact': admin_contact,
425            'RegistrantContact': registrant_contact,
426            'TechContact': tech_contact,
427        }
428        if idn_lang_code is not None:
429            params['IdnLangCode'] = idn_lang_code
430        if auto_renew is not None:
431            params['AutoRenew'] = auto_renew
432        if privacy_protect_admin_contact is not None:
433            params['PrivacyProtectAdminContact'] = privacy_protect_admin_contact
434        if privacy_protect_registrant_contact is not None:
435            params['PrivacyProtectRegistrantContact'] = privacy_protect_registrant_contact
436        if privacy_protect_tech_contact is not None:
437            params['PrivacyProtectTechContact'] = privacy_protect_tech_contact
438        return self.make_request(action='RegisterDomain',
439                                 body=json.dumps(params))
440
441    def retrieve_domain_auth_code(self, domain_name):
442        """
443        This operation returns the AuthCode for the domain. To
444        transfer a domain to another registrar, you provide this value
445        to the new registrar.
446
447        :type domain_name: string
448        :param domain_name: The name of a domain.
449        Type: String
450
451        Default: None
452
453        Constraints: The domain name can contain only the letters a through z,
454            the numbers 0 through 9, and hyphen (-). Internationalized Domain
455            Names are not supported.
456
457        Required: Yes
458
459        """
460        params = {'DomainName': domain_name, }
461        return self.make_request(action='RetrieveDomainAuthCode',
462                                 body=json.dumps(params))
463
464    def transfer_domain(self, domain_name, duration_in_years, nameservers,
465                        admin_contact, registrant_contact, tech_contact,
466                        idn_lang_code=None, auth_code=None, auto_renew=None,
467                        privacy_protect_admin_contact=None,
468                        privacy_protect_registrant_contact=None,
469                        privacy_protect_tech_contact=None):
470        """
471        This operation transfers a domain from another registrar to
472        Amazon Route 53. Domains are registered by the AWS registrar,
473        Gandi upon transfer.
474
475        To transfer a domain, you need to meet all the domain transfer
476        criteria, including the following:
477
478
479        + You must supply nameservers to transfer a domain.
480        + You must disable the domain transfer lock (if any) before
481          transferring the domain.
482        + A minimum of 60 days must have elapsed since the domain's
483          registration or last transfer.
484
485
486        We recommend you use the Amazon Route 53 as the DNS service
487        for your domain. You can create a hosted zone in Amazon Route
488        53 for your current domain before transferring your domain.
489
490        Note that upon transfer, the domain duration is extended for a
491        year if not otherwise specified. Autorenew is enabled by
492        default.
493
494        If the transfer is successful, this method returns an
495        operation ID that you can use to track the progress and
496        completion of the action. If the request is not completed
497        successfully, the domain registrant will be notified by email.
498
499        Transferring domains charges your AWS account an amount based
500        on the top-level domain. For more information, see `Amazon
501        Route 53 Pricing`_.
502
503        :type domain_name: string
504        :param domain_name: The name of a domain.
505        Type: String
506
507        Default: None
508
509        Constraints: The domain name can contain only the letters a through z,
510            the numbers 0 through 9, and hyphen (-). Internationalized Domain
511            Names are not supported.
512
513        Required: Yes
514
515        :type idn_lang_code: string
516        :param idn_lang_code: Reserved for future use.
517
518        :type duration_in_years: integer
519        :param duration_in_years: The number of years the domain will be
520            registered. Domains are registered for a minimum of one year. The
521            maximum period depends on the top-level domain.
522        Type: Integer
523
524        Default: 1
525
526        Valid values: Integer from 1 to 10
527
528        Required: Yes
529
530        :type nameservers: list
531        :param nameservers: Contains details for the host and glue IP
532            addresses.
533        Type: Complex
534
535        Children: `GlueIps`, `Name`
536
537        :type auth_code: string
538        :param auth_code: The authorization code for the domain. You get this
539            value from the current registrar.
540        Type: String
541
542        Required: Yes
543
544        :type auto_renew: boolean
545        :param auto_renew: Indicates whether the domain will be automatically
546            renewed (true) or not (false). Autorenewal only takes effect after
547            the account is charged.
548        Type: Boolean
549
550        Valid values: `True` | `False`
551
552        Default: true
553
554        Required: No
555
556        :type admin_contact: dict
557        :param admin_contact: Provides detailed contact information.
558        Type: Complex
559
560        Children: `FirstName`, `MiddleName`, `LastName`, `ContactType`,
561            `OrganizationName`, `AddressLine1`, `AddressLine2`, `City`,
562            `State`, `CountryCode`, `ZipCode`, `PhoneNumber`, `Email`, `Fax`,
563            `ExtraParams`
564
565        Required: Yes
566
567        :type registrant_contact: dict
568        :param registrant_contact: Provides detailed contact information.
569        Type: Complex
570
571        Children: `FirstName`, `MiddleName`, `LastName`, `ContactType`,
572            `OrganizationName`, `AddressLine1`, `AddressLine2`, `City`,
573            `State`, `CountryCode`, `ZipCode`, `PhoneNumber`, `Email`, `Fax`,
574            `ExtraParams`
575
576        Required: Yes
577
578        :type tech_contact: dict
579        :param tech_contact: Provides detailed contact information.
580        Type: Complex
581
582        Children: `FirstName`, `MiddleName`, `LastName`, `ContactType`,
583            `OrganizationName`, `AddressLine1`, `AddressLine2`, `City`,
584            `State`, `CountryCode`, `ZipCode`, `PhoneNumber`, `Email`, `Fax`,
585            `ExtraParams`
586
587        Required: Yes
588
589        :type privacy_protect_admin_contact: boolean
590        :param privacy_protect_admin_contact: Whether you want to conceal
591            contact information from WHOIS queries. If you specify true, WHOIS
592            ("who is") queries will return contact information for our
593            registrar partner, Gandi, instead of the contact information that
594            you enter.
595        Type: Boolean
596
597        Default: `True`
598
599        Valid values: `True` | `False`
600
601        Required: No
602
603        :type privacy_protect_registrant_contact: boolean
604        :param privacy_protect_registrant_contact: Whether you want to conceal
605            contact information from WHOIS queries. If you specify true, WHOIS
606            ("who is") queries will return contact information for our
607            registrar partner, Gandi, instead of the contact information that
608            you enter.
609        Type: Boolean
610
611        Default: `True`
612
613        Valid values: `True` | `False`
614
615        Required: No
616
617        :type privacy_protect_tech_contact: boolean
618        :param privacy_protect_tech_contact: Whether you want to conceal
619            contact information from WHOIS queries. If you specify true, WHOIS
620            ("who is") queries will return contact information for our
621            registrar partner, Gandi, instead of the contact information that
622            you enter.
623        Type: Boolean
624
625        Default: `True`
626
627        Valid values: `True` | `False`
628
629        Required: No
630
631        """
632        params = {
633            'DomainName': domain_name,
634            'DurationInYears': duration_in_years,
635            'Nameservers': nameservers,
636            'AdminContact': admin_contact,
637            'RegistrantContact': registrant_contact,
638            'TechContact': tech_contact,
639        }
640        if idn_lang_code is not None:
641            params['IdnLangCode'] = idn_lang_code
642        if auth_code is not None:
643            params['AuthCode'] = auth_code
644        if auto_renew is not None:
645            params['AutoRenew'] = auto_renew
646        if privacy_protect_admin_contact is not None:
647            params['PrivacyProtectAdminContact'] = privacy_protect_admin_contact
648        if privacy_protect_registrant_contact is not None:
649            params['PrivacyProtectRegistrantContact'] = privacy_protect_registrant_contact
650        if privacy_protect_tech_contact is not None:
651            params['PrivacyProtectTechContact'] = privacy_protect_tech_contact
652        return self.make_request(action='TransferDomain',
653                                 body=json.dumps(params))
654
655    def update_domain_contact(self, domain_name, admin_contact=None,
656                              registrant_contact=None, tech_contact=None):
657        """
658        This operation updates the contact information for a
659        particular domain. Information for at least one contact
660        (registrant, administrator, or technical) must be supplied for
661        update.
662
663        If the update is successful, this method returns an operation
664        ID that you can use to track the progress and completion of
665        the action. If the request is not completed successfully, the
666        domain registrant will be notified by email.
667
668        :type domain_name: string
669        :param domain_name: The name of a domain.
670        Type: String
671
672        Default: None
673
674        Constraints: The domain name can contain only the letters a through z,
675            the numbers 0 through 9, and hyphen (-). Internationalized Domain
676            Names are not supported.
677
678        Required: Yes
679
680        :type admin_contact: dict
681        :param admin_contact: Provides detailed contact information.
682        Type: Complex
683
684        Children: `FirstName`, `MiddleName`, `LastName`, `ContactType`,
685            `OrganizationName`, `AddressLine1`, `AddressLine2`, `City`,
686            `State`, `CountryCode`, `ZipCode`, `PhoneNumber`, `Email`, `Fax`,
687            `ExtraParams`
688
689        Required: Yes
690
691        :type registrant_contact: dict
692        :param registrant_contact: Provides detailed contact information.
693        Type: Complex
694
695        Children: `FirstName`, `MiddleName`, `LastName`, `ContactType`,
696            `OrganizationName`, `AddressLine1`, `AddressLine2`, `City`,
697            `State`, `CountryCode`, `ZipCode`, `PhoneNumber`, `Email`, `Fax`,
698            `ExtraParams`
699
700        Required: Yes
701
702        :type tech_contact: dict
703        :param tech_contact: Provides detailed contact information.
704        Type: Complex
705
706        Children: `FirstName`, `MiddleName`, `LastName`, `ContactType`,
707            `OrganizationName`, `AddressLine1`, `AddressLine2`, `City`,
708            `State`, `CountryCode`, `ZipCode`, `PhoneNumber`, `Email`, `Fax`,
709            `ExtraParams`
710
711        Required: Yes
712
713        """
714        params = {'DomainName': domain_name, }
715        if admin_contact is not None:
716            params['AdminContact'] = admin_contact
717        if registrant_contact is not None:
718            params['RegistrantContact'] = registrant_contact
719        if tech_contact is not None:
720            params['TechContact'] = tech_contact
721        return self.make_request(action='UpdateDomainContact',
722                                 body=json.dumps(params))
723
724    def update_domain_contact_privacy(self, domain_name, admin_privacy=None,
725                                      registrant_privacy=None,
726                                      tech_privacy=None):
727        """
728        This operation updates the specified domain contact's privacy
729        setting. When the privacy option is enabled, personal
730        information such as postal or email address is hidden from the
731        results of a public WHOIS query. The privacy services are
732        provided by the AWS registrar, Gandi. For more information,
733        see the `Gandi privacy features`_.
734
735        This operation only affects the privacy of the specified
736        contact type (registrant, administrator, or tech). Successful
737        acceptance returns an operation ID that you can use with
738        GetOperationDetail to track the progress and completion of the
739        action. If the request is not completed successfully, the
740        domain registrant will be notified by email.
741
742        :type domain_name: string
743        :param domain_name: The name of a domain.
744        Type: String
745
746        Default: None
747
748        Constraints: The domain name can contain only the letters a through z,
749            the numbers 0 through 9, and hyphen (-). Internationalized Domain
750            Names are not supported.
751
752        Required: Yes
753
754        :type admin_privacy: boolean
755        :param admin_privacy: Whether you want to conceal contact information
756            from WHOIS queries. If you specify true, WHOIS ("who is") queries
757            will return contact information for our registrar partner, Gandi,
758            instead of the contact information that you enter.
759        Type: Boolean
760
761        Default: None
762
763        Valid values: `True` | `False`
764
765        Required: No
766
767        :type registrant_privacy: boolean
768        :param registrant_privacy: Whether you want to conceal contact
769            information from WHOIS queries. If you specify true, WHOIS ("who
770            is") queries will return contact information for our registrar
771            partner, Gandi, instead of the contact information that you enter.
772        Type: Boolean
773
774        Default: None
775
776        Valid values: `True` | `False`
777
778        Required: No
779
780        :type tech_privacy: boolean
781        :param tech_privacy: Whether you want to conceal contact information
782            from WHOIS queries. If you specify true, WHOIS ("who is") queries
783            will return contact information for our registrar partner, Gandi,
784            instead of the contact information that you enter.
785        Type: Boolean
786
787        Default: None
788
789        Valid values: `True` | `False`
790
791        Required: No
792
793        """
794        params = {'DomainName': domain_name, }
795        if admin_privacy is not None:
796            params['AdminPrivacy'] = admin_privacy
797        if registrant_privacy is not None:
798            params['RegistrantPrivacy'] = registrant_privacy
799        if tech_privacy is not None:
800            params['TechPrivacy'] = tech_privacy
801        return self.make_request(action='UpdateDomainContactPrivacy',
802                                 body=json.dumps(params))
803
804    def update_domain_nameservers(self, domain_name, nameservers):
805        """
806        This operation replaces the current set of name servers for
807        the domain with the specified set of name servers. If you use
808        Amazon Route 53 as your DNS service, specify the four name
809        servers in the delegation set for the hosted zone for the
810        domain.
811
812        If successful, this operation returns an operation ID that you
813        can use to track the progress and completion of the action. If
814        the request is not completed successfully, the domain
815        registrant will be notified by email.
816
817        :type domain_name: string
818        :param domain_name: The name of a domain.
819        Type: String
820
821        Default: None
822
823        Constraints: The domain name can contain only the letters a through z,
824            the numbers 0 through 9, and hyphen (-). Internationalized Domain
825            Names are not supported.
826
827        Required: Yes
828
829        :type nameservers: list
830        :param nameservers: A list of new name servers for the domain.
831        Type: Complex
832
833        Children: `Name`, `GlueIps`
834
835        Required: Yes
836
837        """
838        params = {
839            'DomainName': domain_name,
840            'Nameservers': nameservers,
841        }
842        return self.make_request(action='UpdateDomainNameservers',
843                                 body=json.dumps(params))
844
845    def make_request(self, action, body):
846        headers = {
847            'X-Amz-Target': '%s.%s' % (self.TargetPrefix, action),
848            'Host': self.region.endpoint,
849            'Content-Type': 'application/x-amz-json-1.1',
850            'Content-Length': str(len(body)),
851        }
852        http_request = self.build_base_http_request(
853            method='POST', path='/', auth_path='/', params={},
854            headers=headers, data=body)
855        response = self._mexe(http_request, sender=None,
856                              override_num_retries=10)
857        response_body = response.read().decode('utf-8')
858        boto.log.debug(response_body)
859        if response.status == 200:
860            if response_body:
861                return json.loads(response_body)
862        else:
863            json_body = json.loads(response_body)
864            fault_name = json_body.get('__type', None)
865            exception_class = self._faults.get(fault_name, self.ResponseError)
866            raise exception_class(response.status, response.reason,
867                                  body=json_body)
868
869