libcloud-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From to...@apache.org
Subject git commit: Add support for Google DNS API.
Date Mon, 28 Apr 2014 14:15:42 GMT
Repository: libcloud
Updated Branches:
  refs/heads/trunk 08d7d95db -> 865431320


Add support for Google DNS API.

Google recently added a new API for DNS management. This new driver
implement simple operations to create and view zones and records.

Closes #269

Signed-off-by: Tomaz Muraus <tomaz@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/86543132
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/86543132
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/86543132

Branch: refs/heads/trunk
Commit: 865431320488b4a425171bf618ede7937df6549e
Parents: 08d7d95
Author: Franck Cuny <franck.cuny@gmail.com>
Authored: Wed Mar 26 09:29:34 2014 -0700
Committer: Tomaz Muraus <tomaz@apache.org>
Committed: Mon Apr 28 15:54:12 2014 +0200

----------------------------------------------------------------------
 CHANGES.rst                                     |   4 +
 libcloud/dns/drivers/google.py                  | 343 +++++++++++++++++++
 libcloud/dns/providers.py                       |   2 +-
 libcloud/dns/types.py                           |   1 +
 .../google/get_zone_does_not_exists.json        |  13 +
 .../dns/fixtures/google/managed_zones_1.json    |   1 +
 .../test/dns/fixtures/google/no_record.json     |   5 +
 libcloud/test/dns/fixtures/google/record.json   |  17 +
 .../test/dns/fixtures/google/records_list.json  |   1 +
 .../test/dns/fixtures/google/zone_create.json   |   1 +
 .../test/dns/fixtures/google/zone_list.json     |   1 +
 libcloud/test/dns/test_google.py                | 179 ++++++++++
 libcloud/test/secrets.py-dist                   |   2 +
 13 files changed, 569 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/86543132/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index 89bf70e..382c987 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -119,6 +119,10 @@ DNS
   user to create a record with multiple values with a single call.
   [Tomaz Muraus]
 
+- Add new driver for Google DNS.
+  (GITHUB-269)
+  [Franck Cuny]
+
 Changes with Apache Libcloud 0.14.1
 -----------------------------------
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/86543132/libcloud/dns/drivers/google.py
----------------------------------------------------------------------
diff --git a/libcloud/dns/drivers/google.py b/libcloud/dns/drivers/google.py
new file mode 100644
index 0000000..aabc783
--- /dev/null
+++ b/libcloud/dns/drivers/google.py
@@ -0,0 +1,343 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+__all__ = [
+    'GoogleDNSDriver'
+]
+
+API_VERSION = 'v1beta1'
+
+import re
+from libcloud.common.google import GoogleResponse, GoogleBaseConnection
+from libcloud.common.google import ResourceNotFoundError
+from libcloud.dns.types import Provider, RecordType
+from libcloud.dns.types import ZoneDoesNotExistError, RecordDoesNotExistError
+from libcloud.dns.base import DNSDriver, Zone, Record
+
+
+class GoogleDNSResponse(GoogleResponse):
+    pass
+
+
+class GoogleDNSConnection(GoogleBaseConnection):
+    host = "www.googleapis.com"
+    responseCls = GoogleDNSResponse
+
+    def __init__(self, user_id, key, secure, auth_type=None,
+                 credential_file=None, project=None):
+        self.scope = [
+            'https://www.googleapis.com/auth/ndev.clouddns.readwrite'
+        ]
+        super(GoogleDNSConnection, self).\
+            __init__(user_id, key, secure=secure, auth_type=auth_type,
+                     credential_file=credential_file)
+        self.request_path = '/dns/%s/projects/%s' % (API_VERSION, project)
+
+
+class GoogleDNSDriver(DNSDriver):
+    type = Provider.GOOGLE
+    name = 'Google DNS'
+    connectionCls = GoogleDNSConnection
+    website = 'https://cloud.google.com/'
+
+    RECORD_TYPE_MAP = {
+        RecordType.A: 'A',
+        RecordType.AAAA: 'AAAA',
+        RecordType.CNAME: 'CNAME',
+        RecordType.MX: 'MX',
+        RecordType.NS: 'NS',
+        RecordType.PTR: 'PTR',
+        RecordType.SOA: 'SOA',
+        RecordType.SPF: 'SPF',
+        RecordType.SRV: 'SRV',
+        RecordType.TXT: 'TXT',
+    }
+
+    def __init__(self, user_id, key, project=None, auth_type=None):
+        self.auth_type = auth_type
+        self.project = project
+        if not self.project:
+            raise ValueError('Project name must be specified using '
+                             '"project" keyword.')
+        super(GoogleDNSDriver, self).__init__(user_id, key)
+
+    def iterate_zones(self):
+        """
+        Return a generator to iterate over available zones.
+
+        :rtype: ``generator`` of :class:`Zone`
+        """
+        return self._get_more('zones')
+
+    def iterate_records(self, zone):
+        """
+        Return a generator to iterate over records for the provided zone.
+
+        :param zone: Zone to list records for.
+        :type zone: :class:`Zone`
+
+        :rtype: ``generator`` of :class:`Record`
+        """
+        return self._get_more('records', zone=zone)
+
+    def get_zone(self, zone_id):
+        """
+        Return a Zone instance.
+
+        :param zone_id: ID of the required zone
+        :type  zone_id: ``str``
+
+        :rtype: :class:`Zone`
+        """
+        request = '/managedZones/%s' % (zone_id)
+
+        try:
+            response = self.connection.request(request, method='GET').object
+        except ResourceNotFoundError:
+            raise ZoneDoesNotExistError(value='',
+                                        driver=self.connection.driver,
+                                        zone_id=zone_id)
+
+        return self._to_zone(response)
+
+    def get_record(self, zone_id, record_id):
+        """
+        Return a Record instance.
+
+        :param zone_id: ID of the required zone
+        :type  zone_id: ``str``
+
+        :param record_id: ID of the required record
+        :type  record_id: ``str``
+
+        :rtype: :class:`Record`
+        """
+        (record_name, record_type) = record_id.split('-')
+
+        params = {
+            'name': record_name,
+            'type': record_type,
+        }
+
+        request = '/managedZones/%s/rrsets' % (zone_id)
+
+        try:
+            response = self.connection.request(request, method='GET',
+                                               params=params).object
+        except ResourceNotFoundError:
+            raise ZoneDoesNotExistError(value='',
+                                        driver=self.connection.driver,
+                                        zone_id=zone_id)
+
+        if len(response['rrsets']) > 0:
+            return self._to_record(response['rrsets'][0], zone_id)
+
+        raise RecordDoesNotExistError(value='', driver=self.connection.driver,
+                                      record_id=record_id)
+
+    def create_zone(self, domain, type='master', ttl=None, extra=None):
+        """
+        Create a new zone.
+
+        :param domain: Zone domain name (e.g. example.com.) with a \'.\'
+                       at the end.
+        :type domain: ``str``
+
+        :param type: Zone type (master is the only one supported).
+        :type  type: ``str``
+
+        :param ttl: TTL for new records. (unused)
+        :type  ttl: ``int``
+
+        :param extra: Extra attributes (driver specific). (optional)
+        :type extra: ``dict``
+
+        :rtype: :class:`Zone`
+        """
+        name = None
+        description = ''
+
+        if extra:
+            description = extra.get('description')
+            name = extra.get('name')
+
+        if name is None:
+            name = self._cleanup_domain(domain)
+
+        data = {
+            'dnsName': domain,
+            'name': name,
+            'description': description,
+        }
+
+        request = '/managedZones'
+        response = self.connection.request(request, method='POST',
+                                           data=data).object
+        return self._to_zone(response)
+
+    def create_record(self, name, zone, type, data, extra=None):
+        """
+        Create a new record.
+
+        :param name: Record name fully qualified, with a \'.\' at the end.
+        :type  name: ``str``
+
+        :param zone: Zone where the requested record is created.
+        :type  zone: :class:`Zone`
+
+        :param type: DNS record type (A, AAAA, ...).
+        :type  type: :class:`RecordType`
+
+        :param data: Data for the record (depends on the record type).
+        :type  data: ``str``
+
+        :param extra: Extra attributes. (optional)
+        :type extra: ``dict``
+
+        :rtype: :class:`Record`
+        """
+        ttl = data.get('ttl', None)
+        rrdatas = data.get('rrdatas', [])
+
+        data = {
+            'additions': [
+                {
+                    'name': name,
+                    'type': type,
+                    'ttl': int(ttl),
+                    'rrdatas': rrdatas,
+                }
+            ]
+        }
+        request = '/managedZones/%s/changes' % (zone.id)
+        response = self.connection.request(request, method='POST',
+                                           data=data).object
+        return self._to_record(response['additions'][0], zone)
+
+    def delete_zone(self, zone):
+        """
+        Delete a zone.
+
+        Note: This will delete all the records belonging to this zone.
+
+        :param zone: Zone to delete.
+        :type  zone: :class:`Zone`
+
+        :rtype: ``bool``
+        """
+        request = '/managedZones/%s' % (zone.id)
+        response = self.connection.request(request, method='DELETE')
+        return response.success()
+
+    def delete_record(self, record):
+        """
+        Delete a record.
+
+        :param record: Record to delete.
+        :type  record: :class:`Record`
+
+        :rtype: ``bool``
+        """
+        data = {
+            'deletions': [
+                {
+                    'name': record.name,
+                    'type': record.type,
+                    'rrdatas': record.data['rrdatas'],
+                    'ttl': record.data['ttl']
+                }
+            ]
+        }
+        request = '/managedZones/%s/changes' % (record.zone.id)
+        response = self.connection.request(request, method='POST',
+                                           data=data)
+        return response.success()
+
+    def _get_more(self, rtype, **kwargs):
+        last_key = None
+        exhausted = False
+        while not exhausted:
+            items, last_key, exhausted = self._get_data(rtype, last_key,
+                                                        **kwargs)
+            for item in items:
+                yield item
+
+    def _get_data(self, rtype, last_key, **kwargs):
+        params = {}
+
+        if last_key:
+            params['pageToken'] = last_key
+
+        if rtype == 'zones':
+            request = '/managedZones'
+            transform_func = self._to_zones
+            r_key = 'managedZones'
+        elif rtype == 'records':
+            zone = kwargs['zone']
+            request = '/managedZones/%s/rrsets' % (zone.id)
+            transform_func = self._to_records
+            r_key = 'rrsets'
+
+        response = self.connection.request(request, method='GET',
+                                           params=params,)
+
+        if response.success():
+            nextpage = response.object.get('nextPageToken', None)
+            items = transform_func(response.object.get(r_key), **kwargs)
+            exhausted = False if nextpage is not None else True
+            return items, nextpage, exhausted
+        else:
+            return [], None, True
+
+    def _ex_connection_class_kwargs(self):
+        return {'auth_type': self.auth_type,
+                'project': self.project}
+
+    def _to_zones(self, response):
+        zones = []
+        for r in response:
+            zones.append(self._to_zone(r))
+        return zones
+
+    def _to_zone(self, r):
+        extra = {}
+
+        if 'description' in r:
+            extra['description'] = r.get('description')
+
+        extra['creationTime'] = r.get('creationTime')
+        extra['nameServers'] = r.get('nameServers')
+
+        return Zone(id=r['id'], domain=r['dnsName'],
+                    type='master', ttl=0, driver=self, extra=extra)
+
+    def _to_records(self, response, zone):
+        records = []
+        for r in response:
+            records.append(self._to_record(r, zone))
+        return records
+
+    def _to_record(self, r, zone):
+        record_id = '%s-%s' % (r['name'], r['type'])
+        return Record(id=record_id, name=r['name'],
+                      type=r['type'], data=r, zone=zone,
+                      driver=self, extra={})
+
+    def _cleanup_domain(self, domain):
+        # name can only contain lower case alphanumeric characters and hyphens
+        domain = re.sub(r'[^a-zA-Z0-9-]', '-', domain)
+        if domain[-1] == '-':
+            domain = domain[:-1]
+        return domain

http://git-wip-us.apache.org/repos/asf/libcloud/blob/86543132/libcloud/dns/providers.py
----------------------------------------------------------------------
diff --git a/libcloud/dns/providers.py b/libcloud/dns/providers.py
index 53aa724..64483a4 100644
--- a/libcloud/dns/providers.py
+++ b/libcloud/dns/providers.py
@@ -32,7 +32,7 @@ DRIVERS = {
     ('libcloud.dns.drivers.route53', 'Route53DNSDriver'),
     Provider.GANDI:
     ('libcloud.dns.drivers.gandi', 'GandiDNSDriver'),
-
+    Provider.GOOGLE: ('libcloud.dns.drivers.google', 'GoogleDNSDriver'),
     # Deprecated
     Provider.RACKSPACE_US:
     ('libcloud.dns.drivers.rackspace', 'RackspaceUSDNSDriver'),

http://git-wip-us.apache.org/repos/asf/libcloud/blob/86543132/libcloud/dns/types.py
----------------------------------------------------------------------
diff --git a/libcloud/dns/types.py b/libcloud/dns/types.py
index a08f1b0..3b3a79e 100644
--- a/libcloud/dns/types.py
+++ b/libcloud/dns/types.py
@@ -35,6 +35,7 @@ class Provider(object):
     ROUTE53 = 'route53'
     HOSTVIRTUAL = 'hostvirtual'
     GANDI = 'gandi'
+    GOOGLE = 'google'
 
     # Deprecated
     RACKSPACE_US = 'rackspace_us'

http://git-wip-us.apache.org/repos/asf/libcloud/blob/86543132/libcloud/test/dns/fixtures/google/get_zone_does_not_exists.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/google/get_zone_does_not_exists.json b/libcloud/test/dns/fixtures/google/get_zone_does_not_exists.json
new file mode 100644
index 0000000..ddd959d
--- /dev/null
+++ b/libcloud/test/dns/fixtures/google/get_zone_does_not_exists.json
@@ -0,0 +1,13 @@
+{
+ "error": {
+  "errors": [
+   {
+    "domain": "global",
+    "reason": "notFound",
+    "message": "The 'parameters.managedZone' resource named '2' does not exist."
+   }
+  ],
+  "code": 404,
+  "message": "The 'parameters.managedZone' resource named '2' does not exist."
+ }
+}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/86543132/libcloud/test/dns/fixtures/google/managed_zones_1.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/google/managed_zones_1.json b/libcloud/test/dns/fixtures/google/managed_zones_1.json
new file mode 100644
index 0000000..240eb10
--- /dev/null
+++ b/libcloud/test/dns/fixtures/google/managed_zones_1.json
@@ -0,0 +1 @@
+{"kind": "dns#managedZone", "name": "example-com", "nameServers": ["ns-cloud1.googledomains.com.",
"ns-cloud2.googledomains.com.", "ns-cloud3.googledomains.com.", "ns-cloud4.googledomains.com."],
"creationTime": "2014-03-29T23:06:00.921Z", "dnsName": "example.com.", "id": "1", "description":
""}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/86543132/libcloud/test/dns/fixtures/google/no_record.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/google/no_record.json b/libcloud/test/dns/fixtures/google/no_record.json
new file mode 100644
index 0000000..f23c443
--- /dev/null
+++ b/libcloud/test/dns/fixtures/google/no_record.json
@@ -0,0 +1,5 @@
+{
+ "kind": "dns#resourceRecordSetsListResponse",
+ "rrsets": [
+ ]
+}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/86543132/libcloud/test/dns/fixtures/google/record.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/google/record.json b/libcloud/test/dns/fixtures/google/record.json
new file mode 100644
index 0000000..c1bb807
--- /dev/null
+++ b/libcloud/test/dns/fixtures/google/record.json
@@ -0,0 +1,17 @@
+{
+ "kind": "dns#resourceRecordSetsListResponse",
+ "rrsets": [
+  {
+   "kind": "dns#resourceRecordSet",
+   "name": "foo.example.com.",
+   "type": "A",
+   "ttl": 21600,
+   "rrdatas": [
+    "ns-cloud-c1.googledomains.com.",
+    "ns-cloud-c2.googledomains.com.",
+    "ns-cloud-c3.googledomains.com.",
+    "ns-cloud-c4.googledomains.com."
+   ]
+  }
+ ]
+}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/86543132/libcloud/test/dns/fixtures/google/records_list.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/google/records_list.json b/libcloud/test/dns/fixtures/google/records_list.json
new file mode 100644
index 0000000..3c3f2b1
--- /dev/null
+++ b/libcloud/test/dns/fixtures/google/records_list.json
@@ -0,0 +1 @@
+{"rrsets": [{"rrdatas": ["ns-cloud-d1.googledomains.com.", "ns-cloud-d2.googledomains.com.",
"ns-cloud-d3.googledomains.com.", "ns-cloud-d4.googledomains.com."], "kind": "dns#resourceRecordSet",
"type": "NS", "name": "example.com.", "ttl": 21600}, {"rrdatas": ["ns-cloud-d1.googledomains.com.
dns-admin.google.com. 0 21600 3600 1209600 300"], "kind": "dns#resourceRecordSet", "type":
"SOA", "name": "example.com.", "ttl": 21600}, {"rrdatas": ["1.2.3.4"], "kind": "dns#resourceRecordSet",
"type": "A", "name": "foo.example.com.", "ttl": 3600}], "kind": "dns#resourceRecordSetsListResponse"}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/86543132/libcloud/test/dns/fixtures/google/zone_create.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/google/zone_create.json b/libcloud/test/dns/fixtures/google/zone_create.json
new file mode 100644
index 0000000..bdaafdd
--- /dev/null
+++ b/libcloud/test/dns/fixtures/google/zone_create.json
@@ -0,0 +1 @@
+{"kind": "dns#managedZone", "name": "example-org", "nameServers": ["ns-cloud-b1.googledomains.com.",
"ns-cloud-b2.googledomains.com.", "ns-cloud-b3.googledomains.com.", "ns-cloud-b4.googledomains.com."],
"creationTime": "2014-03-30T04:44:20.834Z", "dnsName": "example.org.", "id": "3", "description":
"new domain for example.org"}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/86543132/libcloud/test/dns/fixtures/google/zone_list.json
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/google/zone_list.json b/libcloud/test/dns/fixtures/google/zone_list.json
new file mode 100644
index 0000000..b3f0fd7
--- /dev/null
+++ b/libcloud/test/dns/fixtures/google/zone_list.json
@@ -0,0 +1 @@
+{"kind": "dns#managedZonesListResponse", "managedZones": [{"kind": "dns#managedZone", "name":
"example-com", "nameServers": ["ns-cloud-e1.googledomains.com.", "ns-cloud-e2.googledomains.com.",
"ns-cloud-e3.googledomains.com.", "ns-cloud-e4.googledomains.com."], "creationTime": "2014-03-29T22:45:47.618Z",
"dnsName": "example.com.", "id": "1", "description": ""}, {"kind": "dns#managedZone", "name":
"example-net", "nameServers": ["ns-cloud-d1.googledomains.com.", "ns-cloud-d2.googledomains.com.",
"ns-cloud-d3.googledomains.com.", "ns-cloud-d4.googledomains.com."], "creationTime": "2014-03-29T22:45:46.990Z",
"dnsName": "example.net.", "id": "2", "description": ""}]}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/86543132/libcloud/test/dns/test_google.py
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/test_google.py b/libcloud/test/dns/test_google.py
new file mode 100644
index 0000000..2a4b8c7
--- /dev/null
+++ b/libcloud/test/dns/test_google.py
@@ -0,0 +1,179 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+
+import sys
+import unittest
+
+from libcloud.utils.py3 import httplib
+
+from libcloud.dns.types import ZoneDoesNotExistError
+from libcloud.dns.types import RecordDoesNotExistError
+from libcloud.dns.drivers.google import GoogleDNSDriver
+from libcloud.common.google import (GoogleBaseAuthConnection,
+                                    GoogleInstalledAppAuthConnection,
+                                    GoogleBaseConnection)
+
+from libcloud.test.common.test_google import GoogleAuthMockHttp
+from libcloud.test import MockHttpTestCase, LibcloudTestCase
+from libcloud.test.file_fixtures import DNSFileFixtures
+from libcloud.test.secrets import DNS_PARAMS_GOOGLE, DNS_KEYWORD_PARAMS_GOOGLE
+
+
+class GoogleTests(LibcloudTestCase):
+    GoogleBaseConnection._get_token_info_from_file = lambda x: None
+    GoogleBaseConnection._write_token_info_to_file = lambda x: None
+    GoogleInstalledAppAuthConnection.get_code = lambda x: '1234'
+
+    def setUp(self):
+        GoogleDNSMockHttp.test = self
+        GoogleDNSDriver.connectionCls.conn_classes = (GoogleDNSMockHttp,
+                                                      GoogleDNSMockHttp)
+        GoogleBaseAuthConnection.conn_classes = (GoogleAuthMockHttp,
+                                                 GoogleAuthMockHttp)
+        GoogleDNSMockHttp.type = None
+        kwargs = DNS_KEYWORD_PARAMS_GOOGLE.copy()
+        kwargs['auth_type'] = 'IA'
+        self.driver = GoogleDNSDriver(*DNS_PARAMS_GOOGLE, **kwargs)
+
+    def test_list_zones(self):
+        zones = self.driver.list_zones()
+        self.assertEqual(len(zones), 2)
+
+    def test_list_records(self):
+        zone = self.driver.list_zones()[0]
+        records = self.driver.list_records(zone=zone)
+        self.assertEqual(len(records), 3)
+
+    def test_get_zone(self):
+        zone = self.driver.get_zone(1)
+        self.assertEqual(zone.id, '1')
+        self.assertEqual(zone.domain, 'example.com.')
+
+    def test_get_zone_does_not_exist(self):
+        GoogleDNSMockHttp.type = 'ZONE_DOES_NOT_EXIST'
+
+        try:
+            self.driver.get_zone(2)
+        except ZoneDoesNotExistError:
+            e = sys.exc_info()[1]
+            self.assertEqual(e.zone_id, 2)
+        else:
+            self.fail('Exception not thrown')
+
+    def test_get_record(self):
+        GoogleDNSMockHttp.type = 'FILTER_ZONES'
+        zone = self.driver.list_zones()[0]
+        record = self.driver.get_record(zone.id, "foo.example.com.-A")
+        self.assertEqual(record.name, 'foo.example.com.')
+        self.assertEqual(record.type, 'A')
+
+    def test_get_record_zone_does_not_exist(self):
+        GoogleDNSMockHttp.type = 'ZONE_DOES_NOT_EXIST'
+
+        try:
+            self.driver.get_record(2, 'a-a')
+        except ZoneDoesNotExistError:
+            e = sys.exc_info()[1]
+            self.assertEqual(e.zone_id, 2)
+        else:
+            self.fail('Exception not thrown')
+
+    def test_get_record_record_does_not_exist(self):
+        GoogleDNSMockHttp.type = 'RECORD_DOES_NOT_EXIST'
+        try:
+            self.driver.get_record(1, "foo-A")
+        except RecordDoesNotExistError:
+            e = sys.exc_info()[1]
+            self.assertEqual(e.record_id, 'foo-A')
+        else:
+            self.fail('Exception not thrown')
+
+    def test_create_zone(self):
+        extra = {'description': 'new domain for example.org'}
+        zone = self.driver.create_zone('example.org.', extra)
+        self.assertEqual(zone.domain, 'example.org.')
+        self.assertEqual(zone.extra['description'], extra['description'])
+        self.assertEqual(len(zone.extra['nameServers']), 4)
+
+    def test_delete_zone(self):
+        zone = self.driver.get_zone(1)
+        res = self.driver.delete_zone(zone)
+        self.assertTrue(res)
+
+
+class GoogleDNSMockHttp(MockHttpTestCase):
+    fixtures = DNSFileFixtures('google')
+
+    def _dns_v1beta1_projects_project_name_managedZones(self, method, url,
+                                                        body, headers):
+        if method == 'POST':
+            body = self.fixtures.load('zone_create.json')
+        else:
+            body = self.fixtures.load('zone_list.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _dns_v1beta1_projects_project_name_managedZones_FILTER_ZONES(
+            self, method, url, body, headers):
+        body = self.fixtures.load('zone_list.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _dns_v1beta1_projects_project_name_managedZones_1_rrsets_FILTER_ZONES(
+            self, method, url, body, headers):
+        body = self.fixtures.load('record.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _dns_v1beta1_projects_project_name_managedZones_1_rrsets(
+            self, method, url, body, headers):
+        body = self.fixtures.load('records_list.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _dns_v1beta1_projects_project_name_managedZones_1(self, method,
+                                                          url, body,
+                                                          headers):
+        if method == 'GET':
+            body = self.fixtures.load('managed_zones_1.json')
+        elif method == 'DELETE':
+            body = None
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _dns_v1beta1_projects_project_name_managedZones_2_ZONE_DOES_NOT_EXIST(
+            self, method, url, body, headers):
+        body = self.fixtures.load('get_zone_does_not_exists.json')
+        return (httplib.NOT_FOUND, body, {},
+                httplib.responses[httplib.NOT_FOUND])
+
+    def _dns_v1beta1_projects_project_name_managedZones_3_ZONE_DOES_NOT_EXIST(
+            self, method, url, body, headers):
+        body = self.fixtures.load('get_zone_does_not_exists.json')
+        return (httplib.NOT_FOUND, body, {},
+                httplib.responses[httplib.NOT_FOUND])
+
+    def _dns_v1beta1_projects_project_name_managedZones_1_RECORD_DOES_NOT_EXIST(
+            self, method, url, body, headers):
+        body = self.fixtures.load('managed_zones_1.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _dns_v1beta1_projects_project_name_managedZones_1_rrsets_RECORD_DOES_NOT_EXIST(
+            self, method, url, body, headers):
+        body = self.fixtures.load('no_record.json')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _dns_v1beta1_projects_project_name_managedZones_2_rrsets_ZONE_DOES_NOT_EXIST(
+            self, method, url, body, headers):
+        body = self.fixtures.load('get_zone_does_not_exists.json')
+        return (httplib.NOT_FOUND, body, {},
+                httplib.responses[httplib.NOT_FOUND])
+
+if __name__ == '__main__':
+    sys.exit(unittest.main())

http://git-wip-us.apache.org/repos/asf/libcloud/blob/86543132/libcloud/test/secrets.py-dist
----------------------------------------------------------------------
diff --git a/libcloud/test/secrets.py-dist b/libcloud/test/secrets.py-dist
index 773a2c2..030176e 100644
--- a/libcloud/test/secrets.py-dist
+++ b/libcloud/test/secrets.py-dist
@@ -63,3 +63,5 @@ DNS_PARAMS_RACKSPACE = ('user', 'key')
 DNS_PARAMS_HOSTVIRTUAL = ('key',)
 DNS_PARAMS_ROUTE53 = ('access_id', 'secret')
 DNS_GANDI = ('user', )
+DNS_PARAMS_GOOGLE = ('email_address', 'key')
+DNS_KEYWORD_PARAMS_GOOGLE = {'project': 'project_name'}


Mime
View raw message