diff --git a/cloudcafe/designate/client.py b/cloudcafe/designate/client.py new file mode 100644 index 00000000..17609b9c --- /dev/null +++ b/cloudcafe/designate/client.py @@ -0,0 +1,29 @@ +""" +Copyright 2014 Rackspace + +Licensed 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. +""" + +from cafe.engine.http.client import AutoMarshallingHTTPClient + + +class DesignateClient(AutoMarshallingHTTPClient): + + def __init__(self, url, serialize_format, deserialize_format): + super(DesignateClient, self).__init__(serialize_format, + deserialize_format) + self.url = url.rstrip('/') + self.default_headers['Content-Type'] = 'application/{0}'.format( + self.serialize_format) + self.default_headers['Accept'] = 'application/{0}'.format( + self.deserialize_format) diff --git a/cloudcafe/designate/v1/domain_api/client.py b/cloudcafe/designate/v1/domain_api/client.py index 388c9601..cf55c577 100644 --- a/cloudcafe/designate/v1/domain_api/client.py +++ b/cloudcafe/designate/v1/domain_api/client.py @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. """ -from cafe.engine.clients.rest import AutoMarshallingRestClient +from cloudcafe.designate.client import DesignateClient from cloudcafe.designate.v1.domain_api.models.requests import DomainRequest from cloudcafe.designate.v1.domain_api.models.responses import ( DomainResponse, DomainListResponse) @@ -22,17 +22,12 @@ from cloudcafe.designate.v1.server_api.models.responses import ( ServerResponse, ServerListResponse) -class DomainAPIClient(AutoMarshallingRestClient): +class DomainAPIClient(DesignateClient): def __init__(self, url, serialize_format=None, deserialize_format=None): - super(DomainAPIClient, self).__init__(serialize_format, + super(DomainAPIClient, self).__init__(url, serialize_format, deserialize_format) - self.url = url.rstrip('/') - self.default_headers['Content-Type'] = 'application/{0}'.format( - self.serialize_format) - self.default_headers['Accept'] = 'application/{0}'.format( - self.serialize_format) def _get_domains_url(self): return "{0}/domains".format(self.url) diff --git a/cloudcafe/designate/v1/quotas_api/__init__.py b/cloudcafe/designate/v1/quotas_api/__init__.py new file mode 100644 index 00000000..59ab77fa --- /dev/null +++ b/cloudcafe/designate/v1/quotas_api/__init__.py @@ -0,0 +1,15 @@ +""" +Copyright 2013 Rackspace + +Licensed 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. +""" diff --git a/cloudcafe/designate/v1/quotas_api/client.py b/cloudcafe/designate/v1/quotas_api/client.py new file mode 100644 index 00000000..a5a4d335 --- /dev/null +++ b/cloudcafe/designate/v1/quotas_api/client.py @@ -0,0 +1,57 @@ +""" +Copyright 2013 Rackspace + +Licensed 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. +""" + +from cloudcafe.designate.client import DesignateClient +from cloudcafe.designate.v1.quotas_api.models.requests import QuotasRequest +from cloudcafe.designate.v1.quotas_api.models.responses import QuotasResponse + + +class QuotasAPIClient(DesignateClient): + + def __init__(self, url, serialize_format=None, deserialize_format=None): + super(QuotasAPIClient, self).__init__(url, serialize_format, + deserialize_format) + + def _get_quotas_url(self): + return "{0}/quotas".format(self.url) + + def _get_quota_url(self, tenant_id): + return "{0}/{1}".format(self._get_quotas_url(), tenant_id) + + def update_quotas(self, tenant_id=None, domains=None, + recordset_records=None, domain_records=None, + domain_recordsets=None, **requestslib_kwargs): + """PUT /quotas/{tenantID}""" + quota_req = QuotasRequest(domains=domains, + recordset_records=recordset_records, + domain_records=domain_records, + domain_recordsets=domain_recordsets) + url = self._get_quota_url(tenant_id) + return self.request('PUT', url, response_entity_type=QuotasResponse, + request_entity=quota_req, + requestslib_kwargs=requestslib_kwargs) + + def get_quotas(self, tenant_id, **requestslib_kwargs): + """GET /quotas/{tenantID}""" + url = self._get_quota_url(tenant_id) + return self.request('GET', url, response_entity_type=QuotasResponse, + requestslib_kwargs=requestslib_kwargs) + + def delete_quotas(self, tenant_id, **requestslib_kwargs): + """DELETE /quotas/{tenantID}""" + url = self._get_quota_url(tenant_id) + return self.request('DELETE', url, response_entity_type=QuotasResponse, + requestslib_kwargs=requestslib_kwargs) diff --git a/cloudcafe/designate/v1/quotas_api/models/__init__.py b/cloudcafe/designate/v1/quotas_api/models/__init__.py new file mode 100644 index 00000000..59ab77fa --- /dev/null +++ b/cloudcafe/designate/v1/quotas_api/models/__init__.py @@ -0,0 +1,15 @@ +""" +Copyright 2013 Rackspace + +Licensed 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. +""" diff --git a/cloudcafe/designate/v1/quotas_api/models/requests.py b/cloudcafe/designate/v1/quotas_api/models/requests.py new file mode 100644 index 00000000..d4076f50 --- /dev/null +++ b/cloudcafe/designate/v1/quotas_api/models/requests.py @@ -0,0 +1,38 @@ +""" +Copyright 2013 Rackspace + +Licensed 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. +""" + +import json + +from cafe.engine.models.base import AutoMarshallingModel + + +class QuotasRequest(AutoMarshallingModel): + + def __init__(self, domains=None, recordset_records=None, + domain_records=None, domain_recordsets=None): + self.domains = domains + self.recordset_records = recordset_records + self.domain_records = domain_records + self.domain_recordsets = domain_recordsets + + def _obj_to_json(self): + return json.dumps(self._obj_to_dict()) + + def _obj_to_dict(self): + return {"domain_records": self.domain_records, + "domain_recordsets": self.domain_recordsets, + "domains": self.domains, + "recordset_records": self.recordset_records} diff --git a/cloudcafe/designate/v1/quotas_api/models/responses.py b/cloudcafe/designate/v1/quotas_api/models/responses.py new file mode 100644 index 00000000..ddc7a691 --- /dev/null +++ b/cloudcafe/designate/v1/quotas_api/models/responses.py @@ -0,0 +1,37 @@ +""" +Copyright 2013 Rackspace + +Licensed 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. +""" + +import json + +from cafe.engine.models.base import AutoMarshallingModel + + +class QuotasResponse(AutoMarshallingModel): + + def __init__(self, domains=None, recordset_records=None, + domain_records=None, domain_recordsets=None): + self.domains = domains + self.recordset_records = recordset_records + self.domain_records = domain_records + self.domain_recordsets = domain_recordsets + + @classmethod + def _json_to_obj(cls, serialized_str): + response_json = json.loads(serialized_str) + return QuotasResponse(response_json.get('domains'), + response_json.get('recordset_records'), + response_json.get('domains_records'), + response_json.get('domains_recordsets')) diff --git a/cloudcafe/designate/v1/record_api/__init__.py b/cloudcafe/designate/v1/record_api/__init__.py new file mode 100644 index 00000000..59ab77fa --- /dev/null +++ b/cloudcafe/designate/v1/record_api/__init__.py @@ -0,0 +1,15 @@ +""" +Copyright 2013 Rackspace + +Licensed 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. +""" diff --git a/cloudcafe/designate/v1/record_api/client.py b/cloudcafe/designate/v1/record_api/client.py new file mode 100644 index 00000000..5d901962 --- /dev/null +++ b/cloudcafe/designate/v1/record_api/client.py @@ -0,0 +1,79 @@ +""" +Copyright 2013 Rackspace + +Licensed 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. +""" + +from cloudcafe.designate.client import DesignateClient +from cloudcafe.designate.v1.record_api.models.requests import RecordRequest +from cloudcafe.designate.v1.record_api.models.responses import ( + RecordResponse, RecordListResponse) + + +class RecordsAPIClient(DesignateClient): + + def __init__(self, url, serialize_format=None, + deserialize_format=None): + super(RecordsAPIClient, self).__init__(url, serialize_format, + deserialize_format) + + def _get_domain_url(self, domain_id): + return "{0}/domains/{1}".format(self.url, domain_id) + + def _get_records_url(self, domain_id): + return "{0}/records".format(self._get_domain_url(domain_id)) + + def _get_record_url(self, domain_id, record_id): + return "{0}/{1}".format(self._get_records_url(domain_id), record_id) + + def create_record(self, name=None, type=None, + data=None, priority=None, + domain_id=None, requestslib_kwargs=None): + """POST /domains/{domainID}/records""" + record_req = RecordRequest(name=name, data=data, record_type=type, + priority=priority) + url = self._get_records_url(domain_id) + return self.request('POST', url, request_entity=record_req, + response_entity_type=RecordResponse, + requestslib_kwargs=requestslib_kwargs) + + def list_records(self, domain_id, requestslib_kwargs=None): + """GET /domains/{domainID}/records""" + url = self._get_records_url(domain_id) + return self.request('GET', url, + response_entity_type=RecordListResponse, + requestslib_kwargs=requestslib_kwargs) + + def get_record(self, domain_id, record_id, requestslib_kwargs=None): + """GET /domains/{domainID}/records/{recordID}""" + url = self._get_record_url(domain_id, record_id) + return self.request('GET', url, response_entity_type=RecordResponse, + requestslib_kwargs=requestslib_kwargs) + + def update_record(self, domain_id=None, name=None, type=None, data=None, + priority=None, record_id=None, requestslib_kwargs=None): + """PUT /domains/{domainID}/records/{record_id}""" + record_req = RecordRequest(name=name, data=data, + record_type=type, priority=priority) + url = self._get_record_url(domain_id, record_id) + return self.request('PUT', url, + response_entity_type=RecordResponse, + request_entity=record_req, + requestslib_kwargs=requestslib_kwargs) + + def delete_record(self, domain_id, record_id, requestslib_kwargs=None): + """DELETE /domains/{domainID}/records/{recordID}""" + url = self._get_record_url(domain_id, record_id) + return self.request('DELETE', url, + response_entity_type=RecordResponse, + requestslib_kwargs=requestslib_kwargs) diff --git a/cloudcafe/designate/v1/record_api/models/__init__.py b/cloudcafe/designate/v1/record_api/models/__init__.py new file mode 100644 index 00000000..59ab77fa --- /dev/null +++ b/cloudcafe/designate/v1/record_api/models/__init__.py @@ -0,0 +1,15 @@ +""" +Copyright 2013 Rackspace + +Licensed 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. +""" diff --git a/cloudcafe/designate/v1/record_api/models/requests.py b/cloudcafe/designate/v1/record_api/models/requests.py new file mode 100644 index 00000000..834c111a --- /dev/null +++ b/cloudcafe/designate/v1/record_api/models/requests.py @@ -0,0 +1,49 @@ +""" +Copyright 2013 Rackspace + +Licensed 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. +""" + +import json + +from cafe.engine.models.base import AutoMarshallingModel + + +class RecordRequest(AutoMarshallingModel): + + def __init__(self, name=None, record_type=None, data=None, ttl=None, + priority=None): + self.name = name + self.type = record_type + self.data = data + self.ttl = ttl + self.priority = priority + + def _obj_to_json(self): + records = self._obj_to_dict() + return json.dumps(records) + + def _obj_to_dict(self): + """ + { "name": "www.example.com.", + "type": "A", + "data": "192.0.2.3" } + """ + records = { + "name": self.name, + "type": self.type, + "data": self.data, + "ttl": self.ttl, + "priority": self.priority, + } + return self._remove_empty_values(records) diff --git a/cloudcafe/designate/v1/record_api/models/responses.py b/cloudcafe/designate/v1/record_api/models/responses.py new file mode 100644 index 00000000..7370278b --- /dev/null +++ b/cloudcafe/designate/v1/record_api/models/responses.py @@ -0,0 +1,86 @@ +""" +Copyright 2013 Rackspace + +Licensed 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. +""" + +import json + +from cafe.engine.models.base import AutoMarshallingModel +from cafe.engine.models.base import AutoMarshallingListModel + + +class RecordResponse(AutoMarshallingModel): + + def __init__(self, id=None, name=None, type=None, created_at=None, + updated_at=None, domain_id=None, tenant_id=None, ttl=None, + priority=None, data=None, description=None, version=None): + self.id = id + self.name = name + self.type = type + self.ttl = ttl + self.created_at = created_at + self.updated_at = updated_at + self.data = data + self.domain_id = domain_id + self.tenant_id = tenant_id + self.priority = priority + self.description = description + self.version = version + + @classmethod + def _from_dict(cls, record_dict): + """ + { + "id": "2e32e609-3a4f-45ba-bdef-e50eacd345ad", + "name": "www.example.com.", + "type": "A", + "created_at": "2012-11-02T19:56:26.366792", + "updated_at": null, + "domain_id": "89acac79-38e7-497d-807c-a011e1310438", + "ttl": null, + "priority": null, + "data": "192.0.2.3", + "description": null + } + """ + return RecordResponse(id = record_dict.get("id"), + name = record_dict.get("name"), + type = record_dict.get("type"), + ttl = record_dict.get("ttl"), + created_at = record_dict.get("created_at"), + updated_at = record_dict.get("updated_at"), + data = record_dict.get("data"), + domain_id = record_dict.get("domain_id"), + tenant_id = record_dict.get("tenant_id"), + priority = record_dict.get("priority"), + description = record_dict.get("description"), + version = record_dict.get("version")) + + @classmethod + def _json_to_obj(cls, serialized_str): + response_json = json.loads(serialized_str) + return cls._from_dict(response_json) + + +class RecordListResponse(AutoMarshallingListModel): + + @classmethod + def _json_to_obj(cls, serialized_str): + response_json = json.loads(serialized_str) + return cls._list_to_obj(response_json.get("records")) + + @classmethod + def _list_to_obj(cls, record_list): + return RecordListResponse( + [RecordResponse._from_dict(record) for record in record_list]) diff --git a/cloudcafe/designate/v1/server_api/client.py b/cloudcafe/designate/v1/server_api/client.py index 9c843bcf..c8d06129 100644 --- a/cloudcafe/designate/v1/server_api/client.py +++ b/cloudcafe/designate/v1/server_api/client.py @@ -14,23 +14,18 @@ See the License for the specific language governing permissions and limitations under the License. """ -from cafe.engine.clients.rest import AutoMarshallingRestClient +from cloudcafe.designate.client import DesignateClient from cloudcafe.designate.v1.server_api.models.requests import ServerRequest from cloudcafe.designate.v1.server_api.models.responses import \ ServerResponse, ServerListResponse -class ServerAPIClient(AutoMarshallingRestClient): +class ServerAPIClient(DesignateClient): def __init__(self, url, serialize_format=None, deserialize_format=None): - super(ServerAPIClient, self).__init__(serialize_format, + super(ServerAPIClient, self).__init__(url, serialize_format, deserialize_format) - self.url = url.rstrip('/') - self.default_headers['Content-Type'] = 'application/{0}'.format( - self.serialize_format) - self.default_headers['Accept'] = 'application/{0}'.format( - self.serialize_format) def _get_servers_url(self): return "{0}/servers".format(self.url)