From 17a346ad51bf5c3b2032ffd3d854bb4b1d0d2f78 Mon Sep 17 00:00:00 2001 From: Tollef Fog Heen Date: Thu, 2 Jun 2016 13:31:56 +0200 Subject: [PATCH 01/12] Only pass content to status for delete_domain self is an implied parameter. Avoids backtrace. --- fastly/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastly/__init__.py b/fastly/__init__.py index 3cb66f3..c6d2721 100755 --- a/fastly/__init__.py +++ b/fastly/__init__.py @@ -402,7 +402,7 @@ def update_domain(self, service_id, version_number, name_key, **kwargs): def delete_domain(self, service_id, version_number, name): """Delete the domain for a particular service and version.""" content = self._fetch("/service/%s/version/%d/domain/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE") - return self._status(self, content) + return self._status(content) def check_domain(self, service_id, version_number, name): """Checks the status of a domain's DNS record. Returns an array of 3 items. The first is the details for the domain. The second is the current CNAME of the domain. The third is a boolean indicating whether or not it has been properly setup to use Fastly.""" From e76de1feaf91ba3d2251ce6ce50d5c1cd1972ca9 Mon Sep 17 00:00:00 2001 From: Tollef Fog Heen Date: Thu, 2 Jun 2016 13:32:38 +0200 Subject: [PATCH 02/12] Avoid infinite loop in backend.healtcheck() Call __getattr__ directly, else we end up calling ourselves which ends in tears. --- fastly/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastly/__init__.py b/fastly/__init__.py index c6d2721..80867d5 100755 --- a/fastly/__init__.py +++ b/fastly/__init__.py @@ -1136,7 +1136,7 @@ class FastlyBackend(FastlyObject, IServiceVersionObject): @property def healthcheck(self): - return self._conn.get_healthcheck(self.service_id, self.version, self.healthcheck) + return self._conn.get_healthcheck(self.service_id, self.version, self.__getattr__("healthcheck")) class FastlyCacheSettings(FastlyObject, IServiceVersionObject): From ffe78218854681a905d7b7a8c799bc5eeb88c791 Mon Sep 17 00:00:00 2001 From: Tollef Fog Heen Date: Thu, 2 Jun 2016 13:33:29 +0200 Subject: [PATCH 03/12] Comment is valid for conditions, make that available --- fastly/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fastly/__init__.py b/fastly/__init__.py index 80867d5..8eab69b 100755 --- a/fastly/__init__.py +++ b/fastly/__init__.py @@ -1163,6 +1163,7 @@ class FastlyCondition(FastlyObject, IServiceVersionObject): "type", "statement", "priority", + "comment", ] From 452e0468139664fd6ad4725214d18e2bf0abfbba Mon Sep 17 00:00:00 2001 From: Tollef Fog Heen Date: Tue, 25 Oct 2016 09:53:12 +0200 Subject: [PATCH 04/12] Allow retrieving the backends from a director --- fastly/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fastly/__init__.py b/fastly/__init__.py index 8eab69b..4a1bb6f 100755 --- a/fastly/__init__.py +++ b/fastly/__init__.py @@ -1206,6 +1206,7 @@ class FastlyDirector(FastlyObject, IServiceVersionObject, IDateStampedObject): "deleted", "capacity", "comment", + "backends", ] From 2f21e448cbc80814a076302a47d9702f104c2702 Mon Sep 17 00:00:00 2001 From: Tollef Fog Heen Date: Wed, 26 Oct 2016 11:48:56 +0200 Subject: [PATCH 05/12] Use the same keyword name in create_header and update_header --- fastly/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fastly/__init__.py b/fastly/__init__.py index 4a1bb6f..df2a529 100755 --- a/fastly/__init__.py +++ b/fastly/__init__.py @@ -456,11 +456,11 @@ def list_headers(self, service_id, version_number): content = self._fetch("/service/%s/version/%d/header" % (service_id, version_number)) return map(lambda x: FastlyHeader(self, x), content) - def create_header(self, service_id, version_number, name, destination, source, _type=FastlyHeaderType.RESPONSE, action=FastlyHeaderAction.SET, regex=None, substitution=None, ignore_if_set=None, priority=10, response_condition=None, cache_condition=None, request_condition=None): + def create_header(self, service_id, version_number, name, dst, src, _type=FastlyHeaderType.RESPONSE, action=FastlyHeaderAction.SET, regex=None, substitution=None, ignore_if_set=None, priority=10, response_condition=None, cache_condition=None, request_condition=None): body = self._formdata({ "name": name, - "dst": destination, - "src": source, + "dst": dst, + "src": src, "type": _type, "action": action, "regex": regex, From 6c0864bb33e95a9b920925ee2e64883c559f9341 Mon Sep 17 00:00:00 2001 From: Tollef Fog Heen Date: Fri, 18 Nov 2016 09:28:10 +0100 Subject: [PATCH 06/12] Make it possible to use the same kwargs for update_{condition,director,header} as their create_ counterparts --- fastly/__init__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fastly/__init__.py b/fastly/__init__.py index df2a529..fbac8c2 100755 --- a/fastly/__init__.py +++ b/fastly/__init__.py @@ -261,6 +261,8 @@ def get_condition(self, service_id, version_number, name): def update_condition(self, service_id, version_number, name_key, **kwargs): """Updates the specified condition.""" + if '_type' in kwargs: + kwargs['type'] = kwargs['_type'] body = self._formdata(kwargs, FastlyCondition.FIELDS) content = self._fetch("/service/%s/version/%d/condition/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body) return FastlyCondition(self, content) @@ -344,6 +346,8 @@ def get_director(self, service_id, version_number, name): def update_director(self, service_id, version_number, name_key, **kwargs): """Update the director for a particular service and version.""" + if '_type' in kwargs: + kwargs['type'] = kwargs['_type'] body = self._formdata(kwargs, FastlyDirector.FIELDS) content = self._fetch("/service/%s/version/%d/director/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body) return FastlyDirector(self, content) @@ -482,6 +486,8 @@ def get_header(self, service_id, version_number, name): def update_header(self, service_id, version_number, name_key, **kwargs): """Modifies an existing Header object by name.""" + if '_type' in kwargs: + kwargs['type'] = kwargs['_type'] body = self._formdata(kwargs, FastlyHeader.FIELDS) content = self._fetch("/service/%s/version/%d/header/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body) return FastlyHeader(self, content) From ce257ab3c04879c6e2a09c4cafcd722adac9cabd Mon Sep 17 00:00:00 2001 From: Tollef Fog Heen Date: Wed, 15 Mar 2017 09:39:11 +0100 Subject: [PATCH 07/12] Add support for setting SNI host name --- fastly/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fastly/__init__.py b/fastly/__init__.py index fbac8c2..96346d5 100755 --- a/fastly/__init__.py +++ b/fastly/__init__.py @@ -144,7 +144,8 @@ def create_backend( shield=None, request_condition=None, healthcheck=None, - comment=None): + comment=None, + ssl_sni_hostname=None,): """Create a backend for a particular service and version.""" body = self._formdata({ "name": name, @@ -162,6 +163,7 @@ def create_backend( "request_condition": request_condition, "healthcheck": healthcheck, "comment": comment, + "ssl_sni_hostname": ssl_sni_hostname, }, FastlyBackend.FIELDS) content = self._fetch("/service/%s/version/%d/backend" % (service_id, version_number), method="POST", body=body) return FastlyBackend(self, content) @@ -1138,6 +1140,7 @@ class FastlyBackend(FastlyObject, IServiceVersionObject): "request_condition", "healthcheck", "comment", + "ssl_sni_hostname", ] @property From a903710f8dcd3457752d71eaeb0e37b01c0a27b0 Mon Sep 17 00:00:00 2001 From: Tollef Fog Heen Date: Tue, 2 May 2017 10:09:22 +0200 Subject: [PATCH 08/12] Return None if healthcheck is None, rather than trying to retrieve one called None from the API --- fastly/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fastly/__init__.py b/fastly/__init__.py index 96346d5..86ca4a6 100755 --- a/fastly/__init__.py +++ b/fastly/__init__.py @@ -1145,6 +1145,8 @@ class FastlyBackend(FastlyObject, IServiceVersionObject): @property def healthcheck(self): + if self.__getattr__('healthcheck') is None: + return None return self._conn.get_healthcheck(self.service_id, self.version, self.__getattr__("healthcheck")) From fc4c2c27919efa6b85dbf1f4c352f855cb999c75 Mon Sep 17 00:00:00 2001 From: Tollef Fog Heen Date: Sun, 6 Aug 2017 22:08:49 +0200 Subject: [PATCH 09/12] Pass safe='' to urllib.quote Names can (often) contain slashes, so we need to make sure those are encoded as well. --- fastly/__init__.py | 92 +++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/fastly/__init__.py b/fastly/__init__.py index 86ca4a6..bdb844e 100755 --- a/fastly/__init__.py +++ b/fastly/__init__.py @@ -170,18 +170,18 @@ def create_backend( def get_backend(self, service_id, version_number, name): """Get the backend for a particular service and version.""" - content = self._fetch("/service/%s/version/%d/backend/%s" % (service_id, version_number, urllib.quote(name))) + content = self._fetch("/service/%s/version/%d/backend/%s" % (service_id, version_number, urllib.quote(name, safe=''))) return FastlyBackend(self, content) def update_backend(self, service_id, version_number, name_key, **kwargs): """Update the backend for a particular service and version.""" body = self._formdata(kwargs, FastlyBackend.FIELDS) - content = self._fetch("/service/%s/version/%d/backend/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body) + content = self._fetch("/service/%s/version/%d/backend/%s" % (service_id, version_number, urllib.quote(name_key, safe='')), method="PUT", body=body) return FastlyBackend(self, content) def delete_backend(self, service_id, version_number, name): """Delete the backend for a particular service and version.""" - content = self._fetch("/service/%s/version/%d/backend/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE") + content = self._fetch("/service/%s/version/%d/backend/%s" % (service_id, version_number, urllib.quote(name, safe='')), method="DELETE") return self._status(content) def check_backends(self, service_id, version_number): @@ -217,18 +217,18 @@ def create_cache_settings( def get_cache_settings(self, service_id, version_number, name): """Get a specific cache settings object.""" - content = self._fetch("/service/%s/version/%d/cache_settings/%s" % (service_id, version_number, urllib.quote(name))) + content = self._fetch("/service/%s/version/%d/cache_settings/%s" % (service_id, version_number, urllib.quote(name, safe=''))) return FastlyCacheSettings(self, content) def update_cache_settings(self, service_id, version_number, name_key, **kwargs): """Update a specific cache settings object.""" body = self._formdata(kwargs, FastlyCacheSettings.FIELDS) - content = self._fetch("/service/%s/version/%d/cache_settings/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body) + content = self._fetch("/service/%s/version/%d/cache_settings/%s" % (service_id, version_number, urllib.quote(name_key, safe='')), method="PUT", body=body) return FastlyCacheSettings(self, content) def delete_cache_settings(self, service_id, version_number, name): """Delete a specific cache settings object.""" - content = self._fetch("/service/%s/version/%d/cache_settings/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE") + content = self._fetch("/service/%s/version/%d/cache_settings/%s" % (service_id, version_number, urllib.quote(name, safe='')), method="DELETE") return self._status(content) def list_conditions(self, service_id, version_number): @@ -258,7 +258,7 @@ def create_condition( def get_condition(self, service_id, version_number, name): """Gets a specified condition.""" - content = self._fetch("/service/%s/version/%d/condition/%s" % (service_id, version_number, urllib.quote(name))) + content = self._fetch("/service/%s/version/%d/condition/%s" % (service_id, version_number, urllib.quote(name, safe=''))) return FastlyCondition(self, content) def update_condition(self, service_id, version_number, name_key, **kwargs): @@ -266,12 +266,12 @@ def update_condition(self, service_id, version_number, name_key, **kwargs): if '_type' in kwargs: kwargs['type'] = kwargs['_type'] body = self._formdata(kwargs, FastlyCondition.FIELDS) - content = self._fetch("/service/%s/version/%d/condition/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body) + content = self._fetch("/service/%s/version/%d/condition/%s" % (service_id, version_number, urllib.quote(name_key, safe='')), method="PUT", body=body) return FastlyCondition(self, content) def delete_condition(self, service_id, version_number, name): """Deletes the specified condition.""" - content = self._fetch("/service/%s/version/%d/condition/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE") + content = self._fetch("/service/%s/version/%d/condition/%s" % (service_id, version_number, urllib.quote(name, safe='')), method="DELETE") return self._status(content) def content_edge_check(self, url): @@ -343,7 +343,7 @@ def create_director( def get_director(self, service_id, version_number, name): """Get the director for a particular service and version.""" - content = self._fetch("/service/%s/version/%d/director/%s" % (service_id, version_number, urllib.quote(name))) + content = self._fetch("/service/%s/version/%d/director/%s" % (service_id, version_number, urllib.quote(name, safe=''))) return FastlyDirector(self, content) def update_director(self, service_id, version_number, name_key, **kwargs): @@ -351,27 +351,27 @@ def update_director(self, service_id, version_number, name_key, **kwargs): if '_type' in kwargs: kwargs['type'] = kwargs['_type'] body = self._formdata(kwargs, FastlyDirector.FIELDS) - content = self._fetch("/service/%s/version/%d/director/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body) + content = self._fetch("/service/%s/version/%d/director/%s" % (service_id, version_number, urllib.quote(name_key, safe='')), method="PUT", body=body) return FastlyDirector(self, content) def delete_director(self, service_id, version_number, name): """Delete the director for a particular service and version.""" - content = self._fetch("/service/%s/version/%d/director/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE") + content = self._fetch("/service/%s/version/%d/director/%s" % (service_id, version_number, urllib.quote(name, safe='')), method="DELETE") return self._status(content) def get_director_backend(self, service_id, version_number, director_name, backend_name): """Returns the relationship between a Backend and a Director. If the Backend has been associated with the Director, it returns a simple record indicating this. Otherwise, returns a 404.""" - content = self._fetch("/service/%s/version/%d/director/%s/backend/%s" % (service_id, version_number, director_name, urllib.quote(backend_name)), method="GET") + content = self._fetch("/service/%s/version/%d/director/%s/backend/%s" % (service_id, version_number, director_name, urllib.quote(backend_name, safe='')), method="GET") return FastlyDirectorBackend(self, content) def create_director_backend(self, service_id, version_number, director_name, backend_name): """Establishes a relationship between a Backend and a Director. The Backend is then considered a member of the Director and can be used to balance traffic onto.""" - content = self._fetch("/service/%s/version/%d/director/%s/backend/%s" % (service_id, version_number, director_name, urllib.quote(backend_name)), method="POST") + content = self._fetch("/service/%s/version/%d/director/%s/backend/%s" % (service_id, version_number, director_name, urllib.quote(backend_name, safe='')), method="POST") return FastlyDirectorBackend(self, content) def delete_director_backend(self, service_id, version_number, director_name, backend_name): """Deletes the relationship between a Backend and a Director. The Backend is no longer considered a member of the Director and thus will not have traffic balanced onto it from this Director.""" - content = self._fetch("/service/%s/version/%d/director/%s/backend/%s" % (service_id, version_number, director_name, urllib.quote(backend_name)), method="DELETE") + content = self._fetch("/service/%s/version/%d/director/%s/backend/%s" % (service_id, version_number, director_name, urllib.quote(backend_name, safe='')), method="DELETE") return self._status(content) def list_domains(self, service_id, version_number): @@ -396,23 +396,23 @@ def create_domain( def get_domain(self, service_id, version_number, name): """Get the domain for a particular service and version.""" - content = self._fetch("/service/%s/version/%d/domain/%s" % (service_id, version_number, urllib.quote(name))) + content = self._fetch("/service/%s/version/%d/domain/%s" % (service_id, version_number, urllib.quote(name, safe=''))) return FastlyDomain(self, content) def update_domain(self, service_id, version_number, name_key, **kwargs): """Update the domain for a particular service and version.""" body = self._formdata(kwargs, FastlyDomain.FIELDS) - content = self._fetch("/service/%s/version/%d/domain/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body) + content = self._fetch("/service/%s/version/%d/domain/%s" % (service_id, version_number, urllib.quote(name_key, safe='')), method="PUT", body=body) return FastlyDomain(self, content) def delete_domain(self, service_id, version_number, name): """Delete the domain for a particular service and version.""" - content = self._fetch("/service/%s/version/%d/domain/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE") + content = self._fetch("/service/%s/version/%d/domain/%s" % (service_id, version_number, urllib.quote(name, safe='')), method="DELETE") return self._status(content) def check_domain(self, service_id, version_number, name): """Checks the status of a domain's DNS record. Returns an array of 3 items. The first is the details for the domain. The second is the current CNAME of the domain. The third is a boolean indicating whether or not it has been properly setup to use Fastly.""" - content = self._fetch("/service/%s/version/%d/domain/%s/check" % (service_id, version_number, urllib.quote(name))) + content = self._fetch("/service/%s/version/%d/domain/%s/check" % (service_id, version_number, urllib.quote(name, safe=''))) return FastlyDomainCheck(self, content) def check_domains(self, service_id, version_number): @@ -443,18 +443,18 @@ def create_gzip(self, service_id, version_number, name, cache_condition=None, co def get_gzip(self, service_id, version_number, name): """Retrieves a Header object by name.""" - content = self._fetch("/service/%s/version/%d/gzip/%s" % (service_id, version_number, urllib.quote(name))) + content = self._fetch("/service/%s/version/%d/gzip/%s" % (service_id, version_number, urllib.quote(name, safe=''))) return FastlyGzip(self, content) def update_gzip(self, service_id, version_number, name_key, **kwargs): """Modifies an existing Gzip object by name.""" body = self._formdata(kwargs, FastlyGzip.FIELDS) - content = self._fetch("/service/%s/version/%d/gzip/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body) + content = self._fetch("/service/%s/version/%d/gzip/%s" % (service_id, version_number, urllib.quote(name_key, safe='')), method="PUT", body=body) return FastlyGzip(self, content) def delete_gzip(self, service_id, version_number, name): """Deletes a Gzip object by name.""" - content = self._fetch("/service/%s/version/%d/gzip/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE") + content = self._fetch("/service/%s/version/%d/gzip/%s" % (service_id, version_number, urllib.quote(name, safe='')), method="DELETE") return self._status(content) def list_headers(self, service_id, version_number): @@ -483,7 +483,7 @@ def create_header(self, service_id, version_number, name, dst, src, _type=Fastly def get_header(self, service_id, version_number, name): """Retrieves a Header object by name.""" - content = self._fetch("/service/%s/version/%d/header/%s" % (service_id, version_number, urllib.quote(name))) + content = self._fetch("/service/%s/version/%d/header/%s" % (service_id, version_number, urllib.quote(name, safe=''))) return FastlyHeader(self, content) def update_header(self, service_id, version_number, name_key, **kwargs): @@ -491,12 +491,12 @@ def update_header(self, service_id, version_number, name_key, **kwargs): if '_type' in kwargs: kwargs['type'] = kwargs['_type'] body = self._formdata(kwargs, FastlyHeader.FIELDS) - content = self._fetch("/service/%s/version/%d/header/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body) + content = self._fetch("/service/%s/version/%d/header/%s" % (service_id, version_number, urllib.quote(name_key, safe='')), method="PUT", body=body) return FastlyHeader(self, content) def delete_header(self, service_id, version_number, name): """Deletes a Header object by name.""" - content = self._fetch("/service/%s/version/%d/header/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE") + content = self._fetch("/service/%s/version/%d/header/%s" % (service_id, version_number, urllib.quote(name, safe='')), method="DELETE") return self._status(content) def list_healthchecks(self, service_id, version_number): @@ -538,18 +538,18 @@ def create_healthcheck( def get_healthcheck(self, service_id, version_number, name): """Get the healthcheck for a particular service and version.""" - content = self._fetch("/service/%s/version/%d/healthcheck/%s" % (service_id, version_number, urllib.quote(name))) + content = self._fetch("/service/%s/version/%d/healthcheck/%s" % (service_id, version_number, urllib.quote(name, safe=''))) return FastlyHealthCheck(self, content) def update_healthcheck(self, service_id, version_number, name_key, **kwargs): """Update the healthcheck for a particular service and version.""" body = self._formdata(kwargs, FastlyHealthCheck.FIELDS) - content = self._fetch("/service/%s/version/%d/healthcheck/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body) + content = self._fetch("/service/%s/version/%d/healthcheck/%s" % (service_id, version_number, urllib.quote(name_key, safe='')), method="PUT", body=body) return FastlyHealthCheck(self, content) def delete_healthcheck(self, service_id, version_number, name): """Delete the healthcheck for a particular service and version.""" - content = self._fetch("/service/%s/version/%d/healthcheck/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE") + content = self._fetch("/service/%s/version/%d/healthcheck/%s" % (service_id, version_number, urllib.quote(name, safe='')), method="DELETE") return self._status(content) def purge_url(self, host, path): @@ -603,18 +603,18 @@ def create_request_setting( def get_request_setting(self, service_id, version_number, name): """Gets the specified Request Settings object.""" - content = self._fetch("/service/%s/version/%d/request_settings/%s" % (service_id, version_number, urllib.quote(name))) + content = self._fetch("/service/%s/version/%d/request_settings/%s" % (service_id, version_number, urllib.quote(name, safe=''))) return FastlyRequestSetting(self, content) def update_request_setting(self, service_id, version_number, name_key, **kwargs): """Updates the specified Request Settings object.""" body = self._formdata(kwargs, FastlyHealthCheck.FIELDS) - content = self._fetch("/service/%s/version/%d/request_settings/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body) + content = self._fetch("/service/%s/version/%d/request_settings/%s" % (service_id, version_number, urllib.quote(name_key, safe='')), method="PUT", body=body) return FastlyRequestSetting(self, content) def delete_request_setting(self, service_id, version_number, name): """Removes the specfied Request Settings object.""" - content = self._fetch("/service/%s/version/%d/request_settings/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE") + content = self._fetch("/service/%s/version/%d/request_settings/%s" % (service_id, version_number, urllib.quote(name, safe='')), method="DELETE") return self._status(content) def list_response_objects(self, service_id, version_number): @@ -637,18 +637,18 @@ def create_response_object(self, service_id, version_number, name, status="200", def get_response_object(self, service_id, version_number, name): """Gets the specified Response Object.""" - content = self._fetch("/service/%s/version/%d/response_object/%s" % (service_id, version_number, urllib.quote(name))) + content = self._fetch("/service/%s/version/%d/response_object/%s" % (service_id, version_number, urllib.quote(name, safe=''))) return FastlyResponseObject(self, content) def update_response_object(self, service_id, version_number, name_key, **kwargs): """Updates the specified Response Object.""" body = self._formdata(kwargs, FastlyResponseObject.FIELDS) - content = self._fetch("/service/%s/version/%d/response_object/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body) + content = self._fetch("/service/%s/version/%d/response_object/%s" % (service_id, version_number, urllib.quote(name_key, safe='')), method="PUT", body=body) return FastlyResponseObject(self, content) def delete_response_object(self, service_id, version_number, name): """Deletes the specified Response Object.""" - content = self._fetch("/service/%s/version/%d/response_object/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE") + content = self._fetch("/service/%s/version/%d/response_object/%s" % (service_id, version_number, urllib.quote(name, safe='')), method="DELETE") return self._status(content) def create_service(self, customer_id, name, publish_key=None, comment=None): @@ -679,7 +679,7 @@ def get_service_details(self, service_id): def get_service_by_name(self, service_name): """Get a specific service by name.""" - content = self._fetch("/service/search?name=%s" % urllib.quote(service_name)) + content = self._fetch("/service/search?name=%s" % urllib.quote(service_name, safe='')) return FastlyService(self, content) def update_service(self, service_id, **kwargs): @@ -757,18 +757,18 @@ def create_syslog( def get_syslog(self, service_id, version_number, name): """Get the Syslog for a particular service and version.""" - content = self._fetch("/service/%s/version/%d/syslog/%s" % (service_id, version_number, urllib.quote(name))) + content = self._fetch("/service/%s/version/%d/syslog/%s" % (service_id, version_number, urllib.quote(name, safe=''))) return FastlySyslog(self, content) def update_syslog(self, service_id, version_number, name_key, **kwargs): """Update the Syslog for a particular service and version.""" body = self._formdata(kwargs, FastlySyslog.FIELDS) - content = self._fetch("/service/%s/version/%d/syslog/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body) + content = self._fetch("/service/%s/version/%d/syslog/%s" % (service_id, version_number, urllib.quote(name_key, safe='')), method="PUT", body=body) return FastlySyslog(self, content) def delete_syslog(self, service_id, version_number, name): """Delete the Syslog for a particular service and version.""" - content = self._fetch("/service/%s/version/%d/syslog/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE") + content = self._fetch("/service/%s/version/%d/syslog/%s" % (service_id, version_number, urllib.quote(name, safe='')), method="DELETE") return self._status(content) def change_password(self, old_password, new_password): @@ -842,12 +842,12 @@ def download_vcl(self, service_id, version_number, name): def get_vcl(self, service_id, version_number, name, include_content=True): """Get the uploaded VCL for a particular service and version.""" - content = self._fetch("/service/%s/version/%d/vcl/%s?include_content=%d" % (service_id, version_number, urllib.quote(name), int(include_content))) + content = self._fetch("/service/%s/version/%d/vcl/%s?include_content=%d" % (service_id, version_number, urllib.quote(name, safe=''), int(include_content))) return FastlyVCL(self, content) def get_vcl_html(self, service_id, version_number, name): """Get the uploaded VCL for a particular service and version with HTML syntax highlighting.""" - content = self._fetch("/service/%s/version/%d/vcl/%s/content" % (service_id, version_number, urllib.quote(name))) + content = self._fetch("/service/%s/version/%d/vcl/%s/content" % (service_id, version_number, urllib.quote(name, safe=''))) return content.get("content", None) def get_generated_vcl(self, service_id, version_number): @@ -862,18 +862,18 @@ def get_generated_vcl_html(self, service_id, version_number): def set_main_vcl(self, service_id, version_number, name): """Set the specified VCL as the main.""" - content = self._fetch("/service/%s/version/%d/vcl/%s/main" % (service_id, version_number, urllib.quote(name)), method="PUT") + content = self._fetch("/service/%s/version/%d/vcl/%s/main" % (service_id, version_number, urllib.quote(name, safe='')), method="PUT") return FastlyVCL(self, content) def update_vcl(self, service_id, version_number, name_key, **kwargs): """Update the uploaded VCL for a particular service and version.""" body = self._formdata(kwargs, FastlyVCL.FIELDS) - content = self._fetch("/service/%s/version/%d/vcl/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body) + content = self._fetch("/service/%s/version/%d/vcl/%s" % (service_id, version_number, urllib.quote(name_key, safe='')), method="PUT", body=body) return FastlyVCL(self, content) def delete_vcl(self, service_id, version_number, name): """Delete the uploaded VCL for a particular service and version.""" - content = self._fetch("/service/%s/version/%d/vcl/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE") + content = self._fetch("/service/%s/version/%d/vcl/%s" % (service_id, version_number, urllib.quote(name, safe='')), method="DELETE") return self._status(content) def create_version(self, service_id, inherit_service_id=None, comment=None): @@ -949,18 +949,18 @@ def create_wordpress( def get_wordpress(self, service_id, version_number, name): """Get information on a specific wordpress.""" - content = self._fetch("/service/%s/version/%d/wordpress/%s" % (service_id, version_number, urllib.quote(name))) + content = self._fetch("/service/%s/version/%d/wordpress/%s" % (service_id, version_number, urllib.quote(name, safe=''))) return FastlyWordpress(self, content) def update_wordpress(self, service_id, version_number, name_key, **kwargs): """Update a specified wordpress.""" body = self._formdata(kwargs, FastlyWordpress.FIELDS) - content = self._fetch("/service/%s/version/%d/wordpress/%s" % (service_id, version_number, urllib.quote(name_key)), method="PUT", body=body) + content = self._fetch("/service/%s/version/%d/wordpress/%s" % (service_id, version_number, urllib.quote(name_key, safe='')), method="PUT", body=body) return FastlyWordpress(self, content) def delete_wordpress(self, service_id, version_number, name): """Delete a specified wordpress.""" - content = self._fetch("/service/%s/version/%d/wordpress/%s" % (service_id, version_number, urllib.quote(name)), method="DELETE") + content = self._fetch("/service/%s/version/%d/wordpress/%s" % (service_id, version_number, urllib.quote(name, safe='')), method="DELETE") return self._status(content) # TODO: Is this broken? From 94c4f515e6f36ba629d7840333c79de6ecde1584 Mon Sep 17 00:00:00 2001 From: Tollef Fog Heen Date: Tue, 2 May 2017 10:45:16 +0200 Subject: [PATCH 10/12] Add support for setting ssl_cert_hostname --- fastly/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fastly/__init__.py b/fastly/__init__.py index bdb844e..dfaeaee 100755 --- a/fastly/__init__.py +++ b/fastly/__init__.py @@ -145,6 +145,7 @@ def create_backend( request_condition=None, healthcheck=None, comment=None, + ssl_cert_hostname=None, ssl_sni_hostname=None,): """Create a backend for a particular service and version.""" body = self._formdata({ @@ -163,6 +164,7 @@ def create_backend( "request_condition": request_condition, "healthcheck": healthcheck, "comment": comment, + "ssl_cert_hostname": ssl_cert_hostname, "ssl_sni_hostname": ssl_sni_hostname, }, FastlyBackend.FIELDS) content = self._fetch("/service/%s/version/%d/backend" % (service_id, version_number), method="POST", body=body) @@ -1140,6 +1142,7 @@ class FastlyBackend(FastlyObject, IServiceVersionObject): "request_condition", "healthcheck", "comment", + "ssl_cert_hostname", "ssl_sni_hostname", ] From 33f2fb40c2375a62a99f4a61ccd433df2f056c3f Mon Sep 17 00:00:00 2001 From: Tollef Fog Heen Date: Sun, 6 Aug 2017 23:50:11 +0200 Subject: [PATCH 11/12] Treat healthcheck == None and healthcheck == '' the same Fastly's API doesn't properly differentiate between healthcheck-as-a-string and as healthcheck-as-an-object, which means you will get healthcheck == '' back when it says "(none)" in the UI. --- fastly/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastly/__init__.py b/fastly/__init__.py index dfaeaee..03e03b0 100755 --- a/fastly/__init__.py +++ b/fastly/__init__.py @@ -1148,7 +1148,7 @@ class FastlyBackend(FastlyObject, IServiceVersionObject): @property def healthcheck(self): - if self.__getattr__('healthcheck') is None: + if self.__getattr__('healthcheck') is None or self.__getattr__('healthcheck') == '': return None return self._conn.get_healthcheck(self.service_id, self.version, self.__getattr__("healthcheck")) From 5b2a60f67917d8f4ef6891bcfc12c6ad5e9068a9 Mon Sep 17 00:00:00 2001 From: Tollef Fog Heen Date: Thu, 24 Aug 2017 22:02:46 +0200 Subject: [PATCH 12/12] Simplify getattr call somewhat, "" is false in python --- fastly/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastly/__init__.py b/fastly/__init__.py index 03e03b0..b7fa4e7 100755 --- a/fastly/__init__.py +++ b/fastly/__init__.py @@ -1148,7 +1148,7 @@ class FastlyBackend(FastlyObject, IServiceVersionObject): @property def healthcheck(self): - if self.__getattr__('healthcheck') is None or self.__getattr__('healthcheck') == '': + if not self.__getattr__('healthcheck'): return None return self._conn.get_healthcheck(self.service_id, self.version, self.__getattr__("healthcheck"))