Skip to content

Commit

Permalink
Fix googleapis#77 - Initialized gcloud dns.
Browse files Browse the repository at this point in the history
Cleaned up dns.

Addressed comments on dns.

Added function to create changes.

Changed project_id to project and addressed comments.
  • Loading branch information
kleyow committed Apr 27, 2014
1 parent 6ebf806 commit 1bd304d
Show file tree
Hide file tree
Showing 8 changed files with 257 additions and 0 deletions.
84 changes: 84 additions & 0 deletions gcloud/connection.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import httplib2
import json
import urllib

import exceptions


class Connection(object):
Expand Down Expand Up @@ -42,3 +46,83 @@ def http(self):
self._http = self._credentials.authorize(self._http)
return self._http


class JsonConnection(Connection):

API_BASE_URL = 'https://www.googleapis.com'
"""The base of the API call URL."""

_EMPTY = object()
"""A pointer to represent an empty value for default arguments."""

def __init__(self, project=None, *args, **kwargs):

super(JsonConnection, self).__init__(*args, **kwargs)

self.project = project

def build_api_url(self, path, query_params=None, api_base_url=None,
api_version=None):

url = self.API_URL_TEMPLATE.format(
api_base_url=(api_base_url or self.API_BASE_URL),
api_version=(api_version or self.API_VERSION),
path=path)

query_params = query_params or {}
query_params.update({'project': self.project})
url += '?' + urllib.urlencode(query_params)

return url

def make_request(self, method, url, data=None, content_type=None,
headers=None):

headers = headers or {}
headers['Accept-Encoding'] = 'gzip'

if data:
content_length = len(str(data))
else:
content_length = 0

headers['Content-Length'] = content_length

if content_type:
headers['Content-Type'] = content_type

return self.http.request(uri=url, method=method, headers=headers,
body=data)

def api_request(self, method, path=None, query_params=None,
data=None, content_type=None,
api_base_url=None, api_version=None,
expect_json=True):

url = self.build_api_url(path=path, query_params=query_params,
api_base_url=api_base_url,
api_version=api_version)

# Making the executive decision that any dictionary
# data will be sent properly as JSON.
if data and isinstance(data, dict):
data = json.dumps(data)
content_type = 'application/json'

response, content = self.make_request(
method=method, url=url, data=data, content_type=content_type)

# TODO: Add better error handling.
if response.status == 404:
raise exceptions.NotFoundError(response, content)
elif not 200 <= response.status < 300:
raise exceptions.ConnectionError(response, content)

if content and expect_json:
# TODO: Better checking on this header for JSON.
content_type = response.get('content-type', '')
if not content_type.startswith('application/json'):
raise TypeError('Expected JSON, got %s' % content_type)
return json.loads(content)

return content
21 changes: 21 additions & 0 deletions gcloud/dns/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
__version__ = '0.1'

# TODO: Allow specific scopes and authorization levels.
SCOPE = ('https://www.googleapis.com/auth/cloud-platform',
'https://www.googleapis.com/auth/ndev.clouddns.readonly',
'https://www.googleapis.com/auth/ndev.clouddns.readwrite')
"""The scope required for authenticating as a Cloud DNS consumer."""


def get_connection(project, client_email, private_key_path):
from gcloud.credentials import Credentials
from gcloud.dns.connection import Connection

credentials = Credentials.get_for_service_account(
client_email, private_key_path, scope=SCOPE)
return Connection(project=project, credentials=credentials)


def get_zone(zone_name, project, client_email, private_key_path):
connection = get_connection(project, client_email, private_key_path)
return connection.get_zone(zone_name)
63 changes: 63 additions & 0 deletions gcloud/dns/connection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import json

from gcloud import connection
from gcloud.dns.zone import Zone


class Connection(connection.JsonConnection):
API_VERSION = 'v1beta1'
"""The version of the API, used in building the API call's URL."""

API_URL_TEMPLATE = ('{api_base_url}/dns/{api_version}/projects/{path}')
"""A template used to craft the URL pointing toward a particular API call."""

_EMPTY = object()
"""A pointer to represent an empty value for default arguments."""

def __init__(self, project=None, *args, **kwargs):

super(Connection, self).__init__(*args, **kwargs)

self.project = project

def create_zone(self, data):
zone = self.new_zone(data['name'])
response = self.api_request(method='POST', path=zone.path,
data=data)
return Zone.from_dict(response, connection=self)

def delete_zone(self, zone):
zone = self.new_zone(zone)
self.api_request(method='DELETE', path=zone.path +
zone.name)
return True

def get_zone(self, zone):
zone = self.new_zone(zone)
response = self.api_request(method='GET', path=zone.path)
return Zone.from_dict(response['managedZones'][0],
connection=self)

def list_zones(self):
zone = self.new_zone('test')
response = self.api_request(method='GET', path=zone.path)
print json.dumps(response, indent=2)

def new_zone(self, zone):
if isinstance(zone, Zone):
return zone

# Support Python 2 and 3.
try:
string_type = basestring
except NameError:
string_type = str

if isinstance(zone, string_type):
return Zone(connection=self, name=zone)

def create_changes(self, zone, data):
zone = self.new_zone(zone)
self.api_request(method='POST', path=zone.path + zone.name + '/changes',
data=data)
return True
19 changes: 19 additions & 0 deletions gcloud/dns/demo/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import os
from gcloud import dns


__all__ = ['get_connection', 'get_zone' 'CLIENT_EMAIL', 'PRIVATE_KEY_PATH',
'PROJECT']


CLIENT_EMAIL = ''
PRIVATE_KEY_PATH = os.path.join(os.path.dirname(__file__), 'demo.key')
PROJECT = ''


def get_connection():
return dns.get_connection(PROJECT, CLIENT_EMAIL, PRIVATE_KEY_PATH)


def get_zone(zone_name):
return dns.get_zone(zone_name, PROJECT, CLIENT_EMAIL, PRIVATE_KEY_PATH)
8 changes: 8 additions & 0 deletions gcloud/dns/demo/demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Welcome to the gCloud DNS Demo! (hit enter)

# We're going to walk through some of the basics...,
# Don't worry though. You don't need to do anything, just keep hitting enter...

# Let's start by importing the demo module and getting a connection:
from gcloud.dns import demo
connection = demo.get_connection()
6 changes: 6 additions & 0 deletions gcloud/dns/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from gcloud.exceptions import gcloudError
# TODO: Make these super useful.


class DNSError(gcloudError):
pass
38 changes: 38 additions & 0 deletions gcloud/dns/zone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
class Zone(object):

def __init__(self, connection=None, creation_time=None, description=None,
dns_name=None, id=None, kind=None, name=None,
name_servers=None):
self.connection = connection
self.creation_time = creation_time
self.description = description
self.dns_name = dns_name
self.id = id
self.kind = kind
self.name = name
self.name_servers = name_servers

@classmethod
def from_dict(cls, zone_dict, connection=None):

return cls(connection=connection,
creation_time=zone_dict['creationTime'],
description=zone_dict['description'],
dns_name=zone_dict['dnsName'], id=zone_dict['id'],
kind=zone_dict['kind'], name=zone_dict['name'],
name_servers=zone_dict['nameServers'])

@property
def path(self):
"""The URL path to this zone."""

if not self.connection.project:
raise ValueError('Cannot determine path without project name.')

return self.connection.project + '/managedZones/'

def delete(self):
return self.connection.delete_zone(self)

def get(self):
return self.connection.get_zone(self)
18 changes: 18 additions & 0 deletions gcloud/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# TODO: Make these super useful.


class gcloudError(Exception):
pass


class ConnectionError(gcloudError):

def __init__(self, response, content):
message = str(response) + content
super(ConnectionError, self).__init__(message)


class NotFoundError(gcloudError):

def __init__(self, response, content):
self.message = 'GET %s returned a 404.' % (response.url)

0 comments on commit 1bd304d

Please sign in to comment.