From 650df076b0dc2fac8ee943ccfe866bc9567da110 Mon Sep 17 00:00:00 2001 From: Kevin Leyow Date: Mon, 31 Mar 2014 21:31:27 -0500 Subject: [PATCH 1/6] Initialized gcloud dns. --- gcloud/dns/__init__.py | 16 ++++ gcloud/dns/changes.py | 10 ++ gcloud/dns/connection.py | 148 +++++++++++++++++++++++++++++ gcloud/dns/demo/__init__.py | 15 +++ gcloud/dns/demo/demo.key | Bin 0 -> 1732 bytes gcloud/dns/demo/demo.py | 8 ++ gcloud/dns/exceptions.py | 18 ++++ gcloud/dns/extras | 21 ++++ gcloud/dns/managed_zone.py | 39 ++++++++ gcloud/dns/project.py | 29 ++++++ gcloud/dns/resource_record_sets.py | 6 ++ 11 files changed, 310 insertions(+) create mode 100644 gcloud/dns/__init__.py create mode 100644 gcloud/dns/changes.py create mode 100644 gcloud/dns/connection.py create mode 100644 gcloud/dns/demo/__init__.py create mode 100644 gcloud/dns/demo/demo.key create mode 100644 gcloud/dns/demo/demo.py create mode 100644 gcloud/dns/exceptions.py create mode 100644 gcloud/dns/extras create mode 100644 gcloud/dns/managed_zone.py create mode 100644 gcloud/dns/project.py create mode 100644 gcloud/dns/resource_record_sets.py diff --git a/gcloud/dns/__init__.py b/gcloud/dns/__init__.py new file mode 100644 index 000000000000..d344e021c593 --- /dev/null +++ b/gcloud/dns/__init__.py @@ -0,0 +1,16 @@ +__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_name, 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_name=project_name, credentials=credentials) diff --git a/gcloud/dns/changes.py b/gcloud/dns/changes.py new file mode 100644 index 000000000000..bea06f164b96 --- /dev/null +++ b/gcloud/dns/changes.py @@ -0,0 +1,10 @@ +class Changes(object): + + def __init__(self, connection=None, additions=None, deletions=None, id=None, + kind=None, status=None): + self.connection = connection + self.additions = additions + self.deletions = deletions + self.id = id + self.kind = kind + self.status = status diff --git a/gcloud/dns/connection.py b/gcloud/dns/connection.py new file mode 100644 index 000000000000..3e08fb872089 --- /dev/null +++ b/gcloud/dns/connection.py @@ -0,0 +1,148 @@ +import json +import urllib + +from gcloud import connection +from gcloud.dns import exceptions +from gcloud.dns.project import Project +from gcloud.dns.managed_zone import ManagedZone + + +class Connection(connection.Connection): + + API_BASE_URL = 'https://www.googleapis.com' + """The base of the API call URL.""" + + 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_name=None, *args, **kwargs): + + super(Connection, self).__init__(*args, **kwargs) + + self.project_name = project_name + + 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_name}) + 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) + print url + # 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 + + def get_project(self, project): + project = self.new_project(project) + response = self.api_request(method='GET', path=project.path) + return Project.from_dict(response, connection=self) + + def new_project(self, project): + if isinstance(project, Project): + return project + + # Support Python 2 and 3. + try: + string_type = basestring + except NameError: + string_type = str + + if isinstance(project, string_type): + return Project(connection=self) + + def create_managed_zone(self, data): + managed_zone = self.new_managed_zone(data['name']) + response = self.api_request(method='POST', path=managed_zone.path, + data=data) + return ManagedZone.from_dict(response, connection=self) + + def delete_managed_zone(self, managed_zone): + managed_zone = self.new_managed_zone(managed_zone) + self.api_request(method='DELETE', path=managed_zone.path + + managed_zone.name) + return True + + def get_managed_zone(self, managed_zone): + managed_zone = self.new_managed_zone(managed_zone) + response = self.api_request(method='GET', path=managed_zone.path) + return ManagedZone.from_dict(response['managedZones'][0], + connection=self) + + def list_managed_zones(self): + managed_zone = self.new_managed_zone('test') + response = self.api_request(method='GET', path=managed_zone.path) + print json.dumps(response, indent=2) + + def new_managed_zone(self, managed_zone): + if isinstance(managed_zone, ManagedZone): + return managed_zone + + # Support Python 2 and 3. + try: + string_type = basestring + except NameError: + string_type = str + + if isinstance(managed_zone, string_type): + return ManagedZone(connection=self, name=managed_zone) diff --git a/gcloud/dns/demo/__init__.py b/gcloud/dns/demo/__init__.py new file mode 100644 index 000000000000..e8e480ae0d78 --- /dev/null +++ b/gcloud/dns/demo/__init__.py @@ -0,0 +1,15 @@ +import os +from gcloud import dns + + +__all__ = ['get_connection', 'CLIENT_EMAIL', 'PRIVATE_KEY_PATH', + 'PROJECT_NAME'] + + +CLIENT_EMAIL = '524635209885-rda26ks46309o10e0nc8rb7d33rn0hlm@developer.gserviceaccount.com' +PRIVATE_KEY_PATH = os.path.join(os.path.dirname(__file__), 'demo.key') +PROJECT_NAME = 'gceremote' + + +def get_connection(): + return dns.get_connection(PROJECT_NAME, CLIENT_EMAIL, PRIVATE_KEY_PATH) diff --git a/gcloud/dns/demo/demo.key b/gcloud/dns/demo/demo.key new file mode 100644 index 0000000000000000000000000000000000000000..c933626a99b828e0822d2e1c37354692e752c5e3 GIT binary patch literal 1732 zcmY+Dc~laJ7RK34L!KpSXt)hwMk!dROrlOEx#Tv9mT7{fLYhk$)|5&l?vk0}ZaVes zlqmzvXqsra<&2qzmJ2OzxS!k#wbB_o=e?OTe|+bj^L^jFf88IR3wsIzg7I9~PcYSe z$xg|u>Od7>ITscV;ljeU>|i_>y!T%b7zN>iwYKaXTT+K@|KAo|4G1ddg2Z?(s0P0m zruKh(>$oli8Fp2E@M-&+)HlK<6K=MuNZ7OK3j#p^5H5&Abonvo#mX`LWQ<;T0D1?v zOcG7R-caHBpLmn%)s8Til*FApWwu23{PIaz zXxF!D!lMRunply31W+`~Cbntj%nJ%DY>czfUkbMwaw z!(N@cH|-R!2+}z5ltXY9a|>T|pWt59Y49P8 zFZ>EFrr2v8CEk0VHAMuEql)D2-keh2a?SE0;9Vd*`}zDv9tH32#At6V`z6~r>UI@I zd-;$e&@WP-C+wU4o$cIsSxBs^kI9f{zCP4<$gg}ypty#-NItmA@?r=t=xZQa1h zC!Y>6e5-pk9+M@d87bbmn@(wluRJn_)Z!}a*D>+Jvy_6HoXMq*n3g<;02JxJLwa_T z11ZNglv2toJGiBhY1Ay^WnWK{Na({m8NU`A7Rxsylh#57pN&83Ve6>SYh4k~_@Tdo zX-dJlE6XU%(B0mGx%16~=?~L>(`#oOASPg_N6jIRX`==5dVpC}G%LEC^)=AOgHIc0 zq}Sln(8C!$E$87W&W1N^O16Cpc>c5S(Q4f@MF!1;4$p7fndufojbwzH5uEVf{r%yp zNP@OL5)ciz0AK>x06HKR5CRC_(q+8SKP4>!60*~qc|OFDaF9eKS>lNVYm0-VEg%m5 zT~dLSbHSJ`%Mb(vYz@>u3GiQlz`ggzX8JGf<{JV zpz3`ljRkYI%F9PSf8G8knQc)Czeydd>wmaj!L8SQm{19 z?LVmSQlKBS44wJ?%%8)1ff{5<^oq)U#Nl2xBrTnrJM%TdAMV(8QJ0;=)=ylV$hK`l zW4rRL5k~@)3lp@;8cJ!k&!VlCyjWXL^TEu!)_Y29@VQ;nnl^V77R$QFo1_MHn>`KC ziCX6c9mJ&~aY`iMldA-(c18s3TJICVy9+4rZ4D7?y1q-^>nkAt-)orsj|&{TT}k`t z4HdZ7l?33~`zZk&f%%i$EX0?Esl=E_0emChMLIyCK}RtPPrf84?pt0mW4G|zaQxtiZ&;gET?`bdl*&)YLuGbj2~`uxkRc6=4rKIBx8 zXN;o3-^c*VN{w2YD-R9(R0NeA2cJ%k6B_p42U05sm&8t!+wabY@Ip$MseV?IPZGUN!^mmOQc!FV%De*pje&=O^3dQ?%r>IR@$p$N z!_LBiHcg-`$iFM=5Y+bcoh;LyM%f?PewEEZQ=S4}0VGt*uYwE4_bsu`xgFff-IT)qbnD z8&Ad?;Z Date: Tue, 1 Apr 2014 12:54:13 -0500 Subject: [PATCH 2/6] Cleaned up dns. --- gcloud/connection.py | 80 +++++++++++++++++++ gcloud/dns/__init__.py | 4 +- gcloud/dns/connection.py | 118 ++++++----------------------- gcloud/dns/demo/__init__.py | 6 +- gcloud/dns/demo/demo.py | 1 + gcloud/dns/exceptions.py | 4 +- gcloud/dns/managed_zone.py | 39 ---------- gcloud/dns/project.py | 17 +++-- gcloud/dns/resource_record_sets.py | 6 -- gcloud/dns/zone.py | 38 ++++++++++ gcloud/exceptions.py | 2 + 11 files changed, 162 insertions(+), 153 deletions(-) delete mode 100644 gcloud/dns/managed_zone.py delete mode 100644 gcloud/dns/resource_record_sets.py create mode 100644 gcloud/dns/zone.py create mode 100644 gcloud/exceptions.py diff --git a/gcloud/connection.py b/gcloud/connection.py index 35855e89b445..848381f4fc6f 100644 --- a/gcloud/connection.py +++ b/gcloud/connection.py @@ -1,4 +1,6 @@ import httplib2 +import json +import urllib class Connection(object): @@ -42,3 +44,81 @@ 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_id=None, *args, **kwargs): + + super(JsonConnection, self).__init__(*args, **kwargs) + + self.project_id = project_id + + 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_id}) + 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) + print url + # 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 diff --git a/gcloud/dns/__init__.py b/gcloud/dns/__init__.py index d344e021c593..53b4a2a1d142 100644 --- a/gcloud/dns/__init__.py +++ b/gcloud/dns/__init__.py @@ -7,10 +7,10 @@ """The scope required for authenticating as a Cloud DNS consumer.""" -def get_connection(project_name, client_email, private_key_path): +def get_connection(project_id, 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_name=project_name, credentials=credentials) + return Connection(project_id=project_id, credentials=credentials) diff --git a/gcloud/dns/connection.py b/gcloud/dns/connection.py index 3e08fb872089..d1834806f2de 100644 --- a/gcloud/dns/connection.py +++ b/gcloud/dns/connection.py @@ -4,14 +4,10 @@ from gcloud import connection from gcloud.dns import exceptions from gcloud.dns.project import Project -from gcloud.dns.managed_zone import ManagedZone +from gcloud.dns.zone import Zone -class Connection(connection.Connection): - - API_BASE_URL = 'https://www.googleapis.com' - """The base of the API call URL.""" - +class Connection(connection.JsonConnection): API_VERSION = 'v1beta1' """The version of the API, used in building the API call's URL.""" @@ -21,77 +17,11 @@ class Connection(connection.Connection): _EMPTY = object() """A pointer to represent an empty value for default arguments.""" - def __init__(self, project_name=None, *args, **kwargs): + def __init__(self, project_id=None, *args, **kwargs): super(Connection, self).__init__(*args, **kwargs) - self.project_name = project_name - - 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_name}) - 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) - print url - # 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 + self.project_id = project_id def get_project(self, project): project = self.new_project(project) @@ -111,32 +41,32 @@ def new_project(self, project): if isinstance(project, string_type): return Project(connection=self) - def create_managed_zone(self, data): - managed_zone = self.new_managed_zone(data['name']) - response = self.api_request(method='POST', path=managed_zone.path, + def create_zone(self, data): + zone = self.new_zone(data['name']) + response = self.api_request(method='POST', path=zone.path, data=data) - return ManagedZone.from_dict(response, connection=self) + return Zone.from_dict(response, connection=self) - def delete_managed_zone(self, managed_zone): - managed_zone = self.new_managed_zone(managed_zone) - self.api_request(method='DELETE', path=managed_zone.path + - managed_zone.name) + def delete_zone(self, zone): + zone = self.new_zone(zone) + self.api_request(method='DELETE', path=zone.path + + zone.name) return True - def get_managed_zone(self, managed_zone): - managed_zone = self.new_managed_zone(managed_zone) - response = self.api_request(method='GET', path=managed_zone.path) - return ManagedZone.from_dict(response['managedZones'][0], + 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_managed_zones(self): - managed_zone = self.new_managed_zone('test') - response = self.api_request(method='GET', path=managed_zone.path) + 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_managed_zone(self, managed_zone): - if isinstance(managed_zone, ManagedZone): - return managed_zone + def new_zone(self, zone): + if isinstance(zone, Zone): + return zone # Support Python 2 and 3. try: @@ -144,5 +74,5 @@ def new_managed_zone(self, managed_zone): except NameError: string_type = str - if isinstance(managed_zone, string_type): - return ManagedZone(connection=self, name=managed_zone) + if isinstance(zone, string_type): + return Zone(connection=self, name=zone) diff --git a/gcloud/dns/demo/__init__.py b/gcloud/dns/demo/__init__.py index e8e480ae0d78..03ca5ed7f0a4 100644 --- a/gcloud/dns/demo/__init__.py +++ b/gcloud/dns/demo/__init__.py @@ -3,13 +3,13 @@ __all__ = ['get_connection', 'CLIENT_EMAIL', 'PRIVATE_KEY_PATH', - 'PROJECT_NAME'] + 'PROJECT_ID'] CLIENT_EMAIL = '524635209885-rda26ks46309o10e0nc8rb7d33rn0hlm@developer.gserviceaccount.com' PRIVATE_KEY_PATH = os.path.join(os.path.dirname(__file__), 'demo.key') -PROJECT_NAME = 'gceremote' +PROJECT_ID = 'gceremote' def get_connection(): - return dns.get_connection(PROJECT_NAME, CLIENT_EMAIL, PRIVATE_KEY_PATH) + return dns.get_connection(PROJECT_ID, CLIENT_EMAIL, PRIVATE_KEY_PATH) diff --git a/gcloud/dns/demo/demo.py b/gcloud/dns/demo/demo.py index 99d5d2c872a1..8acaded67e1b 100644 --- a/gcloud/dns/demo/demo.py +++ b/gcloud/dns/demo/demo.py @@ -6,3 +6,4 @@ # Let's start by importing the demo module and getting a connection: from gcloud.dns import demo connection = demo.get_connection() +print connection.get_project('gceremote') diff --git a/gcloud/dns/exceptions.py b/gcloud/dns/exceptions.py index d49345043dfb..40e20739dec7 100644 --- a/gcloud/dns/exceptions.py +++ b/gcloud/dns/exceptions.py @@ -1,7 +1,9 @@ +from gcloud.exceptions import gcloudError + # TODO: Make these super useful. -class DNSError(Exception): +class DNSError(gcloudError): pass diff --git a/gcloud/dns/managed_zone.py b/gcloud/dns/managed_zone.py deleted file mode 100644 index ed50b6a26127..000000000000 --- a/gcloud/dns/managed_zone.py +++ /dev/null @@ -1,39 +0,0 @@ -class ManagedZone(object): - - def __init__(self, connection=None, creationTime=None, description=None, - dnsName=None, id=None, kind=None, name=None, nameServers=None): - - self.connection = connection - self.creationTime = creationTime - self.description = description - self.dnsName = dnsName - self.id = id - self.kind = kind - self.name = name - self.nameServers = nameServers - - @property - def path(self): - """The URL path to this managed zone.""" - - if not self.connection.project_name: - raise ValueError('Cannot determine path without project name.') - - return self.connection.project_name + '/managedZones/' - - @classmethod - def from_dict(cls, managed_zone_dict, connection=None): - - return cls(connection=connection, - creationTime=managed_zone_dict['creationTime'], - description=managed_zone_dict['description'], - dnsName=managed_zone_dict['dnsName'], - id=managed_zone_dict['id'], - kind=managed_zone_dict['kind'], name=managed_zone_dict['name'], - nameServers=managed_zone_dict['nameServers']) - - def delete(self): - return self.connection.delete_managed_zone(self) - - def get(self): - return self.connection.get_managed_zone(self) diff --git a/gcloud/dns/project.py b/gcloud/dns/project.py index fbe1950069d7..27889b00cbb5 100644 --- a/gcloud/dns/project.py +++ b/gcloud/dns/project.py @@ -9,21 +9,22 @@ def __init__(self, connection=None, id=None, kind=None, number=None, self.number = number self.quota = quota + @classmethod + def from_dict(cls, project_dict, connection=None): + + return cls(connection=connection, id=project_dict['id'], + kind=project_dict['kind'], number=project_dict['number'], + quota=project_dict['quota']) + @property def path(self): """The URL path to this instances.""" - if not self.connection.project_name: + if not self.connection.project_id: raise ValueError('Cannot determine path without project name.') - return self.connection.project_name + return self.connection.project_id - @classmethod - def from_dict(cls, project_dict, connection=None): - - return cls(connection=connection, id=project_dict['id'], - kind=project_dict['kind'], number=project_dict['number'], - quota=project_dict['quota']) def get(self): return self.connection.get_project(self) diff --git a/gcloud/dns/resource_record_sets.py b/gcloud/dns/resource_record_sets.py deleted file mode 100644 index 4028a4055863..000000000000 --- a/gcloud/dns/resource_record_sets.py +++ /dev/null @@ -1,6 +0,0 @@ -class ResourceRecordSets(object): - - def __init__(self, connection=None, kind=None, name=None, rrdatas=None, - ttl=None, type=None): - - self.connection = connection diff --git a/gcloud/dns/zone.py b/gcloud/dns/zone.py new file mode 100644 index 000000000000..9b43a72dc52c --- /dev/null +++ b/gcloud/dns/zone.py @@ -0,0 +1,38 @@ +class Zone(object): + + def __init__(self, connection=None, creationTime=None, description=None, + dnsName=None, id=None, kind=None, name=None, nameServers=None): + self.connection = connection + self.creationTime = creationTime + self.description = description + self.dnsName = dnsName + self.id = id + self.kind = kind + self.name = name + self.nameServers = nameServers + + @classmethod + def from_dict(cls, zone_dict, connection=None): + + return cls(connection=connection, + creationTime=zone_dict['creationTime'], + description=zone_dict['description'], + dnsName=zone_dict['dnsName'], + id=zone_dict['id'], + kind=zone_dict['kind'], name=zone_dict['name'], + nameServers=zone_dict['nameServers']) + + @property + def path(self): + """The URL path to this zone.""" + + if not self.connection.project_id: + raise ValueError('Cannot determine path without project name.') + + return self.connection.project_id + '/managedZones/' + + def delete(self): + return self.connection.delete_zone(self) + + def get(self): + return self.connection.get_zone(self) diff --git a/gcloud/exceptions.py b/gcloud/exceptions.py new file mode 100644 index 000000000000..ed0afa93ca37 --- /dev/null +++ b/gcloud/exceptions.py @@ -0,0 +1,2 @@ +class gcloudError(Exception): + pass From 415556f1e700987f9b065ad699a3202bbe0d257f Mon Sep 17 00:00:00 2001 From: Kevin Leyow Date: Tue, 1 Apr 2014 14:31:37 -0500 Subject: [PATCH 3/6] Addressed comments on dns. --- gcloud/connection.py | 5 ++++- gcloud/dns/__init__.py | 5 +++++ gcloud/dns/changes.py | 10 ---------- gcloud/dns/connection.py | 23 +---------------------- gcloud/dns/demo/__init__.py | 10 +++++++--- gcloud/dns/demo/demo.key | Bin 1732 -> 0 bytes gcloud/dns/demo/demo.py | 1 - gcloud/dns/exceptions.py | 14 -------------- gcloud/dns/extras | 21 --------------------- gcloud/dns/project.py | 30 ------------------------------ gcloud/dns/zone.py | 18 +++++++++--------- gcloud/exceptions.py | 16 ++++++++++++++++ 12 files changed, 42 insertions(+), 111 deletions(-) delete mode 100644 gcloud/dns/changes.py delete mode 100644 gcloud/dns/demo/demo.key delete mode 100644 gcloud/dns/extras delete mode 100644 gcloud/dns/project.py diff --git a/gcloud/connection.py b/gcloud/connection.py index 848381f4fc6f..aa7cb8f980b4 100644 --- a/gcloud/connection.py +++ b/gcloud/connection.py @@ -2,6 +2,8 @@ import json import urllib +import exceptions + class Connection(object): """A generic connection to Google Cloud Platform. @@ -44,6 +46,7 @@ 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.""" @@ -98,7 +101,7 @@ def api_request(self, method, path=None, query_params=None, url = self.build_api_url(path=path, query_params=query_params, api_base_url=api_base_url, api_version=api_version) - print url + # Making the executive decision that any dictionary # data will be sent properly as JSON. if data and isinstance(data, dict): diff --git a/gcloud/dns/__init__.py b/gcloud/dns/__init__.py index 53b4a2a1d142..66a2eb6eb19a 100644 --- a/gcloud/dns/__init__.py +++ b/gcloud/dns/__init__.py @@ -14,3 +14,8 @@ def get_connection(project_id, client_email, private_key_path): credentials = Credentials.get_for_service_account( client_email, private_key_path, scope=SCOPE) return Connection(project_id=project_id, credentials=credentials) + + +def get_zone(zone_name, project_id, client_email, private_key_path): + connection = get_connection(project_id, client_email, private_key_path) + return connection.get_zone(zone_name) diff --git a/gcloud/dns/changes.py b/gcloud/dns/changes.py deleted file mode 100644 index bea06f164b96..000000000000 --- a/gcloud/dns/changes.py +++ /dev/null @@ -1,10 +0,0 @@ -class Changes(object): - - def __init__(self, connection=None, additions=None, deletions=None, id=None, - kind=None, status=None): - self.connection = connection - self.additions = additions - self.deletions = deletions - self.id = id - self.kind = kind - self.status = status diff --git a/gcloud/dns/connection.py b/gcloud/dns/connection.py index d1834806f2de..b16340a09383 100644 --- a/gcloud/dns/connection.py +++ b/gcloud/dns/connection.py @@ -1,9 +1,6 @@ import json -import urllib from gcloud import connection -from gcloud.dns import exceptions -from gcloud.dns.project import Project from gcloud.dns.zone import Zone @@ -23,24 +20,6 @@ def __init__(self, project_id=None, *args, **kwargs): self.project_id = project_id - def get_project(self, project): - project = self.new_project(project) - response = self.api_request(method='GET', path=project.path) - return Project.from_dict(response, connection=self) - - def new_project(self, project): - if isinstance(project, Project): - return project - - # Support Python 2 and 3. - try: - string_type = basestring - except NameError: - string_type = str - - if isinstance(project, string_type): - return Project(connection=self) - def create_zone(self, data): zone = self.new_zone(data['name']) response = self.api_request(method='POST', path=zone.path, @@ -57,7 +36,7 @@ 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) + connection=self) def list_zones(self): zone = self.new_zone('test') diff --git a/gcloud/dns/demo/__init__.py b/gcloud/dns/demo/__init__.py index 03ca5ed7f0a4..4f8f271280e4 100644 --- a/gcloud/dns/demo/__init__.py +++ b/gcloud/dns/demo/__init__.py @@ -2,14 +2,18 @@ from gcloud import dns -__all__ = ['get_connection', 'CLIENT_EMAIL', 'PRIVATE_KEY_PATH', +__all__ = ['get_connection', 'get_zone' 'CLIENT_EMAIL', 'PRIVATE_KEY_PATH', 'PROJECT_ID'] -CLIENT_EMAIL = '524635209885-rda26ks46309o10e0nc8rb7d33rn0hlm@developer.gserviceaccount.com' +CLIENT_EMAIL = '' PRIVATE_KEY_PATH = os.path.join(os.path.dirname(__file__), 'demo.key') -PROJECT_ID = 'gceremote' +PROJECT_ID = '' def get_connection(): return dns.get_connection(PROJECT_ID, CLIENT_EMAIL, PRIVATE_KEY_PATH) + + +def get_zone(zone_name): + return dns.get_zone(zone_name, PROJECT_ID, CLIENT_EMAIL, PRIVATE_KEY_PATH) diff --git a/gcloud/dns/demo/demo.key b/gcloud/dns/demo/demo.key deleted file mode 100644 index c933626a99b828e0822d2e1c37354692e752c5e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1732 zcmY+Dc~laJ7RK34L!KpSXt)hwMk!dROrlOEx#Tv9mT7{fLYhk$)|5&l?vk0}ZaVes zlqmzvXqsra<&2qzmJ2OzxS!k#wbB_o=e?OTe|+bj^L^jFf88IR3wsIzg7I9~PcYSe z$xg|u>Od7>ITscV;ljeU>|i_>y!T%b7zN>iwYKaXTT+K@|KAo|4G1ddg2Z?(s0P0m zruKh(>$oli8Fp2E@M-&+)HlK<6K=MuNZ7OK3j#p^5H5&Abonvo#mX`LWQ<;T0D1?v zOcG7R-caHBpLmn%)s8Til*FApWwu23{PIaz zXxF!D!lMRunply31W+`~Cbntj%nJ%DY>czfUkbMwaw z!(N@cH|-R!2+}z5ltXY9a|>T|pWt59Y49P8 zFZ>EFrr2v8CEk0VHAMuEql)D2-keh2a?SE0;9Vd*`}zDv9tH32#At6V`z6~r>UI@I zd-;$e&@WP-C+wU4o$cIsSxBs^kI9f{zCP4<$gg}ypty#-NItmA@?r=t=xZQa1h zC!Y>6e5-pk9+M@d87bbmn@(wluRJn_)Z!}a*D>+Jvy_6HoXMq*n3g<;02JxJLwa_T z11ZNglv2toJGiBhY1Ay^WnWK{Na({m8NU`A7Rxsylh#57pN&83Ve6>SYh4k~_@Tdo zX-dJlE6XU%(B0mGx%16~=?~L>(`#oOASPg_N6jIRX`==5dVpC}G%LEC^)=AOgHIc0 zq}Sln(8C!$E$87W&W1N^O16Cpc>c5S(Q4f@MF!1;4$p7fndufojbwzH5uEVf{r%yp zNP@OL5)ciz0AK>x06HKR5CRC_(q+8SKP4>!60*~qc|OFDaF9eKS>lNVYm0-VEg%m5 zT~dLSbHSJ`%Mb(vYz@>u3GiQlz`ggzX8JGf<{JV zpz3`ljRkYI%F9PSf8G8knQc)Czeydd>wmaj!L8SQm{19 z?LVmSQlKBS44wJ?%%8)1ff{5<^oq)U#Nl2xBrTnrJM%TdAMV(8QJ0;=)=ylV$hK`l zW4rRL5k~@)3lp@;8cJ!k&!VlCyjWXL^TEu!)_Y29@VQ;nnl^V77R$QFo1_MHn>`KC ziCX6c9mJ&~aY`iMldA-(c18s3TJICVy9+4rZ4D7?y1q-^>nkAt-)orsj|&{TT}k`t z4HdZ7l?33~`zZk&f%%i$EX0?Esl=E_0emChMLIyCK}RtPPrf84?pt0mW4G|zaQxtiZ&;gET?`bdl*&)YLuGbj2~`uxkRc6=4rKIBx8 zXN;o3-^c*VN{w2YD-R9(R0NeA2cJ%k6B_p42U05sm&8t!+wabY@Ip$MseV?IPZGUN!^mmOQc!FV%De*pje&=O^3dQ?%r>IR@$p$N z!_LBiHcg-`$iFM=5Y+bcoh;LyM%f?PewEEZQ=S4}0VGt*uYwE4_bsu`xgFff-IT)qbnD z8&Ad?;Z Date: Tue, 1 Apr 2014 21:02:36 -0500 Subject: [PATCH 4/6] Added function to create changes. --- gcloud/dns/connection.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gcloud/dns/connection.py b/gcloud/dns/connection.py index b16340a09383..736384b5242d 100644 --- a/gcloud/dns/connection.py +++ b/gcloud/dns/connection.py @@ -55,3 +55,9 @@ def new_zone(self, zone): 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 From bada594304eaa688a98aa201336febd90a6ce885 Mon Sep 17 00:00:00 2001 From: Kevin Leyow Date: Wed, 2 Apr 2014 10:30:48 -0500 Subject: [PATCH 5/6] Changed project_id to project and addressed comments. --- gcloud/connection.py | 7 ++++--- gcloud/dns/__init__.py | 8 ++++---- gcloud/dns/connection.py | 4 ++-- gcloud/dns/demo/__init__.py | 8 ++++---- gcloud/dns/zone.py | 4 ++-- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/gcloud/connection.py b/gcloud/connection.py index aa7cb8f980b4..d13967726a41 100644 --- a/gcloud/connection.py +++ b/gcloud/connection.py @@ -48,17 +48,18 @@ def http(self): 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_id=None, *args, **kwargs): + def __init__(self, project=None, *args, **kwargs): super(JsonConnection, self).__init__(*args, **kwargs) - self.project_id = project_id + self.project = project def build_api_url(self, path, query_params=None, api_base_url=None, api_version=None): @@ -69,7 +70,7 @@ def build_api_url(self, path, query_params=None, api_base_url=None, path=path) query_params = query_params or {} - query_params.update({'project': self.project_id}) + query_params.update({'project': self.project}) url += '?' + urllib.urlencode(query_params) return url diff --git a/gcloud/dns/__init__.py b/gcloud/dns/__init__.py index 66a2eb6eb19a..9fda99a801c1 100644 --- a/gcloud/dns/__init__.py +++ b/gcloud/dns/__init__.py @@ -7,15 +7,15 @@ """The scope required for authenticating as a Cloud DNS consumer.""" -def get_connection(project_id, client_email, private_key_path): +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_id=project_id, credentials=credentials) + return Connection(project=project, credentials=credentials) -def get_zone(zone_name, project_id, client_email, private_key_path): - connection = get_connection(project_id, client_email, private_key_path) +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) diff --git a/gcloud/dns/connection.py b/gcloud/dns/connection.py index 736384b5242d..9a81cc86745f 100644 --- a/gcloud/dns/connection.py +++ b/gcloud/dns/connection.py @@ -14,11 +14,11 @@ class Connection(connection.JsonConnection): _EMPTY = object() """A pointer to represent an empty value for default arguments.""" - def __init__(self, project_id=None, *args, **kwargs): + def __init__(self, project=None, *args, **kwargs): super(Connection, self).__init__(*args, **kwargs) - self.project_id = project_id + self.project = project def create_zone(self, data): zone = self.new_zone(data['name']) diff --git a/gcloud/dns/demo/__init__.py b/gcloud/dns/demo/__init__.py index 4f8f271280e4..dfc75a134988 100644 --- a/gcloud/dns/demo/__init__.py +++ b/gcloud/dns/demo/__init__.py @@ -3,17 +3,17 @@ __all__ = ['get_connection', 'get_zone' 'CLIENT_EMAIL', 'PRIVATE_KEY_PATH', - 'PROJECT_ID'] + 'PROJECT'] CLIENT_EMAIL = '' PRIVATE_KEY_PATH = os.path.join(os.path.dirname(__file__), 'demo.key') -PROJECT_ID = '' +PROJECT = '' def get_connection(): - return dns.get_connection(PROJECT_ID, CLIENT_EMAIL, PRIVATE_KEY_PATH) + return dns.get_connection(PROJECT, CLIENT_EMAIL, PRIVATE_KEY_PATH) def get_zone(zone_name): - return dns.get_zone(zone_name, PROJECT_ID, CLIENT_EMAIL, PRIVATE_KEY_PATH) + return dns.get_zone(zone_name, PROJECT, CLIENT_EMAIL, PRIVATE_KEY_PATH) diff --git a/gcloud/dns/zone.py b/gcloud/dns/zone.py index d620f19eaef9..ccf619a7772c 100644 --- a/gcloud/dns/zone.py +++ b/gcloud/dns/zone.py @@ -26,10 +26,10 @@ def from_dict(cls, zone_dict, connection=None): def path(self): """The URL path to this zone.""" - if not self.connection.project_id: + if not self.connection.project: raise ValueError('Cannot determine path without project name.') - return self.connection.project_id + '/managedZones/' + return self.connection.project + '/managedZones/' def delete(self): return self.connection.delete_zone(self) From 9f661b8ec6ae4b67ac23ef9ef3cd64f92293cfe9 Mon Sep 17 00:00:00 2001 From: Kevin Leyow Date: Sat, 5 Apr 2014 23:54:51 -0500 Subject: [PATCH 6/6] Added some functions. --- gcloud/dns/connection.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gcloud/dns/connection.py b/gcloud/dns/connection.py index 9a81cc86745f..dcbb472a4e9d 100644 --- a/gcloud/dns/connection.py +++ b/gcloud/dns/connection.py @@ -61,3 +61,22 @@ def create_changes(self, zone, data): self.api_request(method='POST', path=zone.path + zone.name + '/changes', data=data) return True + + def new_resource(self, name, type, ttl, rrdatas): + return {'kind': 'dns#resourceRecordSet', 'name': name, 'type': type, + 'ttl': ttl, 'rrdatas': rrdatas} + + def new_change(self): + return {'kind': "dns#change", 'additions': [], 'deletions': []} + + def create_record(self, zone, data): + zone = self.new_zone(zone) + self.api_request(method='POST', path=zone.path + zone.name + '/changes', + data=data) + return True + + def list_records(self, zone): + zone = self.new_zone(zone) + response = self.api_request(method='GET', + path=zone.path + zone.name + '/changes') + print json.dumps(response, indent=2)