From e54139edbbbab93979563d2edcf1e2723e4bda12 Mon Sep 17 00:00:00 2001 From: joaopereiramrf Date: Wed, 29 Nov 2017 23:35:21 +0100 Subject: [PATCH 01/13] add option to upload vcl --- library/fastly_service.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/library/fastly_service.py b/library/fastly_service.py index e0f8521..432e2a0 100644 --- a/library/fastly_service.py +++ b/library/fastly_service.py @@ -62,6 +62,10 @@ required: false description: - List of VCL snippets + upload_vcls: + required: false + description: + - Upload VCL settings: required: false description: @@ -487,6 +491,20 @@ def sort_key(f): return f.name +class FastlyVclUpload(FastlyObject): + schema = { + 'name': dict(required=True, type='str', default=None), + 'content': dict(required=True, type='str', default=None) + } + + def __init__(self, config, validate_choices): + self.name = self.read_config(config, validate_choices, 'name') + self.content = self.read_config(config, validate_choices, 'content') + + def sort_key(f): + return f.name + + class FastlyVclSnippet(FastlyObject): schema = { 'name': dict(required=True, type='str', default=None), @@ -533,6 +551,7 @@ def __init__(self, configuration, validate_choices=True): self.headers = [] self.response_objects = [] self.request_settings = [] + self.uploads = [] self.snippets = [] self.settings = FastlySettings(dict(), validate_choices) @@ -576,6 +595,10 @@ def __init__(self, configuration, validate_choices=True): for response_object in configuration['response_objects']: self.response_objects.append(FastlyResponseObject(response_object, validate_choices)) + if 'uploads' in configuration and configuration['uploads'] is not None: + for upload in configuration['uploads']: + self.uploads.append(FastlyVclUpload(upload, validate_choices)) + if 'snippets' in configuration and configuration['snippets'] is not None: for snippet in configuration['snippets']: self.snippets.append(FastlyVclSnippet(snippet, validate_choices)) @@ -594,6 +617,7 @@ def __eq__(self, other): and sorted(self.headers, key=FastlyHeader.sort_key) == sorted(other.headers, key=FastlyHeader.sort_key) \ and sorted(self.request_settings, key=FastlyRequestSetting.sort_key) == sorted(other.request_settings, key=FastlyRequestSetting.sort_key) \ and sorted(self.response_objects, key=FastlyResponseObject.sort_key) == sorted(other.response_objects, key=FastlyResponseObject.sort_key) \ + and sorted(self.uploads, key=FastlyVclUpload.sort_key) == sorted(other.uploads, key=FastlyVclUpload.sort_key) \ and sorted(self.snippets, key=FastlyVclSnippet.sort_key) == sorted(other.snippets, key=FastlyVclSnippet.sort_key) \ and self.settings == other.settings @@ -797,6 +821,14 @@ def create_response_object(self, service_id, version, response_object): raise Exception("Error creating response object for service %s, version %s (%s)" % ( service_id, version, response.payload['detail'])) + def upload_custom_vcl(self, service_id, version, upload_vcl): + response = self._request('/service/%s/version/%s/vcl' % (service_id, version), 'POST', upload_vcl) + + if response.status == 200: + return response.payload + else: + raise Exception("Error uploading VCL '%s' for service %s, version %s (%s)" % (upload_vcl['name'], service_id, version, response.payload['detail'])) + def create_vcl_snippet(self, service_id, version, vcl_snippet): response = self._request('/service/%s/version/%s/snippet' % (service_id, version), 'POST', vcl_snippet) @@ -888,6 +920,9 @@ def deploy_version_with_configuration(self, service_id, configuration, activate_ for response_object in configuration.response_objects: self.client.create_response_object(service_id, version_number, response_object) + for upload_vcl in configuration.uploads: + self.client.upload_custom_vcl(service_id, version_number, upload_vcl) + for vcl_snippet in configuration.snippets: self.client.create_vcl_snippet(service_id, version_number, vcl_snippet) @@ -931,6 +966,7 @@ def __init__(self): headers=dict(default=None, required=False, type='list'), request_settings=dict(default=None, required=False, type='list'), response_objects=dict(default=None, required=False, type='list'), + upload_vcls=dict(default=None, required=False, type='list'), vcl_snippets=dict(default=None, required=False, type='list'), settings=dict(default=None, required=False, type='dict'), ), @@ -959,6 +995,7 @@ def configuration(self): 'headers': self.module.params['headers'], 'request_settings': self.module.params['request_settings'], 'response_objects': self.module.params['response_objects'], + 'uploads': self.module.params['upload_vcls'], 'snippets': self.module.params['vcl_snippets'], 'settings': self.module.params['settings'] }) From 895df07ad6329121810666830c740dc8aed2b35a Mon Sep 17 00:00:00 2001 From: joaopereiramrf Date: Thu, 30 Nov 2017 12:57:12 +0100 Subject: [PATCH 02/13] add options for origins --- library/fastly_service.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/fastly_service.py b/library/fastly_service.py index 432e2a0..24b85f4 100644 --- a/library/fastly_service.py +++ b/library/fastly_service.py @@ -251,6 +251,9 @@ class FastlyBackend(FastlyObject): 'ssl_hostname': dict(required=False, type='str', default=None), 'ssl_ca_cert': dict(required=False, type='str', default=None, exclude_empty_str=True), 'ssl_cert_hostname': dict(required=False, type='str', default=None, exclude_empty_str=True), + 'ssl_sni_hostname': dict(required=False, type='str', default=None, exclude_empty_str=True), + 'min_tls_version': dict(required=False, type='str', default=None, exclude_empty_str=True), + 'max_tls_version': dict(required=False, type='str', default=None, exclude_empty_str=True), 'shield': dict(required=False, type='str', default=None, exclude_empty_str=True), 'healthcheck': dict(required=False, type='str', default=None, exclude_empty_str=True), 'weight': dict(required=False, type='int', default=100), @@ -269,6 +272,9 @@ def __init__(self, config, validate_choices): self.ssl_hostname = self.read_config(config, validate_choices, 'ssl_hostname') self.ssl_ca_cert = self.read_config(config, validate_choices, 'ssl_ca_cert') self.ssl_cert_hostname = self.read_config(config, validate_choices, 'ssl_cert_hostname') + self.ssl_sni_hostname = self.read_config(config, validate_choices, 'ssl_sni_hostname') + self.min_tls_version = self.read_config(config, validate_choices, 'min_tls_version') + self.max_tls_version = self.read_config(config, validate_choices, 'max_tls_version') self.shield = self.read_config(config, validate_choices, 'shield') self.healthcheck = self.read_config(config, validate_choices, 'healthcheck') self.weight = self.read_config(config, validate_choices, 'weight') From b3263525fe8187908396dc09f94c2870129fd790 Mon Sep 17 00:00:00 2001 From: joaopereiramrf Date: Mon, 18 Dec 2017 15:20:03 +0100 Subject: [PATCH 03/13] add syslog option --- library/fastly_service.py | 82 +++++++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 16 deletions(-) diff --git a/library/fastly_service.py b/library/fastly_service.py index 24b85f4..098952a 100644 --- a/library/fastly_service.py +++ b/library/fastly_service.py @@ -515,7 +515,7 @@ class FastlyVclSnippet(FastlyObject): schema = { 'name': dict(required=True, type='str', default=None), 'dynamic': dict(required=False, type='int', default=0), - 'type': dict(required=False, type='str', default='init'), + 'type': dict(required=False, type='str', default='None'), 'content': dict(required=True, type='str', default=None), 'priority': dict(required=False, type='int', default=100) } @@ -530,6 +530,31 @@ def __init__(self, config, validate_choices): def sort_key(f): return f.name +class FastlySysloglogs(FastlyObject): + schema = { + 'name': dict(required=True, type='str', default=None), + 'format': dict(required=True, type='str', default=None), + 'hostname': dict(required=True, type='str', default=None), + 'port': dict(required=True, type='int', default=None), + 'token': dict(required=False, type='str', default=None), + 'use_tls': dict(required=False, type='str', default=None), + 'tls_ca_cert': dict(required=False, type='str', default=None), + 'tls_hostname': dict(required=False, type='str', default=None) + } + + def __init__(self, config, validate_choices): + self.name = self.read_config(config, validate_choices, 'name') + self.format = self.read_config(config, validate_choices, 'format') + self.hostname = self.read_config(config, validate_choices, 'hostname') + self.port = self.read_config(config, validate_choices, 'port') + self.token = self.read_config(config, validate_choices, 'token') + self.use_tls = self.read_config(config, validate_choices, 'use_tls') + self.tls_ca_cert = self.read_config(config, validate_choices, 'tls_ca_cert') + self.tls_hostname = self.read_config(config, validate_choices, 'tls_hostname') + + def sort_key(f): + return f.name + class FastlySettings(FastlyObject): schema = { @@ -559,6 +584,7 @@ def __init__(self, configuration, validate_choices=True): self.request_settings = [] self.uploads = [] self.snippets = [] + self.sysloglogs = [] self.settings = FastlySettings(dict(), validate_choices) if 'domains' in configuration and configuration['domains'] is not None: @@ -609,23 +635,28 @@ def __init__(self, configuration, validate_choices=True): for snippet in configuration['snippets']: self.snippets.append(FastlyVclSnippet(snippet, validate_choices)) + if 'sysloglogs' in configuration and configuration['sysloglogs'] is not None: + for sysloglog in configuration['sysloglogs']: + self.sysloglogs.append(FastlySysloglogs(sysloglog, validate_choices)) + if 'settings' in configuration and configuration['settings'] is not None: self.settings = FastlySettings(configuration['settings'], validate_choices) def __eq__(self, other): return sorted(self.domains, key=FastlyDomain.sort_key) == sorted(other.domains, key=FastlyDomain.sort_key) \ - and sorted(self.healthchecks, key=FastlyHealthcheck.sort_key) == sorted(other.healthchecks, key=FastlyHealthcheck.sort_key) \ - and sorted(self.backends, key=FastlyBackend.sort_key) == sorted(other.backends, key=FastlyBackend.sort_key) \ - and sorted(self.cache_settings, key=FastlyCacheSettings.sort_key) == sorted(other.cache_settings, key=FastlyCacheSettings.sort_key) \ - and sorted(self.conditions, key=FastlyCondition.sort_key) == sorted(other.conditions, key=FastlyCondition.sort_key) \ - and sorted(self.directors, key=FastlyDirector.sort_key) == sorted(other.directors, key=FastlyDirector.sort_key) \ - and sorted(self.gzips, key=FastlyGzip.sort_key) == sorted(other.gzips, key=FastlyGzip.sort_key) \ - and sorted(self.headers, key=FastlyHeader.sort_key) == sorted(other.headers, key=FastlyHeader.sort_key) \ - and sorted(self.request_settings, key=FastlyRequestSetting.sort_key) == sorted(other.request_settings, key=FastlyRequestSetting.sort_key) \ - and sorted(self.response_objects, key=FastlyResponseObject.sort_key) == sorted(other.response_objects, key=FastlyResponseObject.sort_key) \ - and sorted(self.uploads, key=FastlyVclUpload.sort_key) == sorted(other.uploads, key=FastlyVclUpload.sort_key) \ - and sorted(self.snippets, key=FastlyVclSnippet.sort_key) == sorted(other.snippets, key=FastlyVclSnippet.sort_key) \ - and self.settings == other.settings + and sorted(self.healthchecks, key=FastlyHealthcheck.sort_key) == sorted(other.healthchecks, key=FastlyHealthcheck.sort_key) \ + and sorted(self.backends, key=FastlyBackend.sort_key) == sorted(other.backends, key=FastlyBackend.sort_key) \ + and sorted(self.cache_settings, key=FastlyCacheSettings.sort_key) == sorted(other.cache_settings, key=FastlyCacheSettings.sort_key) \ + and sorted(self.conditions, key=FastlyCondition.sort_key) == sorted(other.conditions, key=FastlyCondition.sort_key) \ + and sorted(self.directors, key=FastlyDirector.sort_key) == sorted(other.directors, key=FastlyDirector.sort_key) \ + and sorted(self.gzips, key=FastlyGzip.sort_key) == sorted(other.gzips, key=FastlyGzip.sort_key) \ + and sorted(self.headers, key=FastlyHeader.sort_key) == sorted(other.headers, key=FastlyHeader.sort_key) \ + and sorted(self.request_settings, key=FastlyRequestSetting.sort_key) == sorted(other.request_settings, key=FastlyRequestSetting.sort_key) \ + and sorted(self.response_objects, key=FastlyResponseObject.sort_key) == sorted(other.response_objects, key=FastlyResponseObject.sort_key) \ + and sorted(self.uploads, key=FastlyVclUpload.sort_key) == sorted(other.uploads, key=FastlyVclUpload.sort_key) \ + and sorted(self.snippets, key=FastlyVclSnippet.sort_key) == sorted(other.snippets, key=FastlyVclSnippet.sort_key) \ + and sorted(self.sysloglogs, key=FastlySysloglogs.sort_key) == sorted(other.sysloglogs, key=FastlySysloglogs.sort_key) \ + and self.settings == other.settings def __ne__(self, other): return not self.__eq__(other) @@ -831,9 +862,13 @@ def upload_custom_vcl(self, service_id, version, upload_vcl): response = self._request('/service/%s/version/%s/vcl' % (service_id, version), 'POST', upload_vcl) if response.status == 200: - return response.payload + response = self._request('/service/%s/version/%s/vcl/Main.vcl/main' % (service_id, version), 'PUT', upload_vcl) + if response.status == 200: + return response.payload + else: + raise Exception("Error uploading VCL '%s' for service %s, version %s (%s)" % (upload_vcl['name'], service_id, version, response.payload['detail'])) else: - raise Exception("Error uploading VCL '%s' for service %s, version %s (%s)" % (upload_vcl['name'], service_id, version, response.payload['detail'])) + raise Exception("Error uploading VCL '%s' for service %s, version %s (%s)" % (upload_vcl['name'], service_id, version, response.payload['detail'])) def create_vcl_snippet(self, service_id, version, vcl_snippet): response = self._request('/service/%s/version/%s/snippet' % (service_id, version), 'POST', vcl_snippet) @@ -843,6 +878,16 @@ def create_vcl_snippet(self, service_id, version, vcl_snippet): else: raise Exception("Error creating VCL snippet '%s' for service %s, version %s (%s)" % (vcl_snippet['name'], service_id, version, response.payload['detail'])) + + def create_sysloglogs(self, service_id, version, create_syslog): + response = self._request('/service/%s/version/%s/logging/syslog' % (service_id, version), 'POST', create_syslog) + + if response.status == 200: + return response.payload + else: + raise Exception("Error creating syslog log '%s' for service %s, version %s (%s)" % (create_syslog['name'], service_id, version, response.payload['detail'])) + + def create_settings(self, service_id, version, settings): response = self._request('/service/%s/version/%s/settings' % (service_id, version), 'PUT', settings) if response.status == 200: @@ -932,6 +977,9 @@ def deploy_version_with_configuration(self, service_id, configuration, activate_ for vcl_snippet in configuration.snippets: self.client.create_vcl_snippet(service_id, version_number, vcl_snippet) + for create_syslog in configuration.sysloglogs: + self.client.create_sysloglogs(service_id, version_number, create_syslog) + if configuration.settings: self.client.create_settings(service_id, version_number, configuration.settings) @@ -973,6 +1021,7 @@ def __init__(self): request_settings=dict(default=None, required=False, type='list'), response_objects=dict(default=None, required=False, type='list'), upload_vcls=dict(default=None, required=False, type='list'), + create_syslogs=dict(default=None, required=False, type='list'), vcl_snippets=dict(default=None, required=False, type='list'), settings=dict(default=None, required=False, type='dict'), ), @@ -1003,6 +1052,7 @@ def configuration(self): 'response_objects': self.module.params['response_objects'], 'uploads': self.module.params['upload_vcls'], 'snippets': self.module.params['vcl_snippets'], + 'sysloglogs': self.module.params['create_syslogs'], 'settings': self.module.params['settings'] }) except FastlyValidationError as err: @@ -1038,4 +1088,4 @@ def main(): if __name__ == '__main__': - main() + main() \ No newline at end of file From ff41ea7df6adc082107b4fad009a1627902eb621 Mon Sep 17 00:00:00 2001 From: joaopereiramrf Date: Sun, 18 Feb 2018 17:33:30 +0100 Subject: [PATCH 04/13] clone when the service exists delete all settings create all settings from scratch --- library/fastly_service.py | 327 +++++++++++++++++++++++++++++++++++++- 1 file changed, 320 insertions(+), 7 deletions(-) diff --git a/library/fastly_service.py b/library/fastly_service.py index 098952a..dc28e5b 100644 --- a/library/fastly_service.py +++ b/library/fastly_service.py @@ -705,6 +705,19 @@ def _request(self, path, method='GET', payload=None, headers=None): conn.request(method, path, body, headers) return FastlyResponse(conn.getresponse()) + def get_active_version(self, service_id): + response = self._request('/service/%s/version/active' % service_id) + if response.status == 200: + cloned_from_version = response.payload['number'] + return cloned_from_version + + def clone_old_version(self, service_id, version_to_clone): + response = self._request('/service/%s/version/%s/clone' % (service_id, version_to_clone), 'PUT') + if response.status == 200: + return response.payload + else: + raise Exception("Could not clone version '%s' for service '%s': %s" % (version_to_clone, service_id, response.payload['detail'])) + def get_service_by_name(self, service_name): response = self._request('/service/search?name=%s' % urllib.quote(service_name)) if response.status == 200: @@ -768,6 +781,14 @@ def deactivate_version(self, service_id, version): raise Exception( "Error deactivating version %s for service %s (%s)" % (version, service_id, response.payload['detail'])) + def get_domain_name(self, service_id, version): + response = self._request('/service/%s/version/%s/domain' % (service_id, version), 'GET') + if response.status == 200: + return response.payload + else: + raise Exception( + "Error retrieving domain for service %s, version %s (%s)" % (service_id, version, response.payload['detail'])) + def create_domain(self, service_id, version, domain): response = self._request('/service/%s/version/%s/domain' % (service_id, version), 'POST', domain) if response.status == 200: @@ -776,6 +797,22 @@ def create_domain(self, service_id, version, domain): raise Exception("Error creating domain for service %s, version %s (%s)" % ( service_id, version, response.payload['detail'])) + def delete_domain(self, service_id, version, domain): + response = self._request('/service/%s/version/%s/domain/%s' % (service_id, version, domain), + 'DELETE') + if response.status == 200: + return response.payload + else: + raise Exception("Error deleting domain %s service %s, version %s (%s)" % (domain, service_id, version, + response.payload['detail'])) + def get_healthcheck_name(self, service_id, version): + response = self._request('/service/%s/version/%s/healthcheck' % (service_id, version), 'GET') + if response.status == 200: + return response.payload + else: + raise Exception("Error getting healthcheck name service %s, version %s (%s)" % (service_id, version, + response.payload['detail'])) + def create_healthcheck(self, service_id, version, healthcheck): response = self._request('/service/%s/version/%s/healthcheck' % (service_id, version), 'POST', healthcheck) if response.status == 200: @@ -784,6 +821,24 @@ def create_healthcheck(self, service_id, version, healthcheck): raise Exception("Error creating healthcheck for service %s, version %s (%s)" % ( service_id, version, response.payload['detail'])) + def delete_healthcheck(self, service_id, version, healthcheck): + response = self._request('/service/%s/version/%s/healthcheck/%s' % (service_id, version, healthcheck), + 'DELETE') + if response.status == 200: + return response.payload + else: + raise Exception("Error deleting healthcheck %s service %s, version %s (%s)" % ( + healthcheck, service_id, version, response.payload['detail'])) + + def get_backend_name(self, service_id, version): + response = self._request('/service/%s/version/%s/backend' % (service_id, version), 'GET') + if response.status == 200: + return response.payload + else: + raise Exception( + "Error retrieving backend for service %s, version %s (%s)" % ( + service_id, version, response.payload['detail'])) + def create_backend(self, service_id, version, backend): response = self._request('/service/%s/version/%s/backend' % (service_id, version), 'POST', backend) if response.status == 200: @@ -792,6 +847,24 @@ def create_backend(self, service_id, version, backend): raise Exception("Error creating backend for service %s, version %s (%s)" % ( service_id, version, response.payload['detail'])) + def delete_backend(self, service_id, version, backend): + response = self._request('/service/%s/version/%s/backend/%s' % (service_id, version, backend), + 'DELETE') + if response.status == 200: + return response.payload + else: + raise Exception("Error deleting backend %s service %s, version %s (%s)" % ( + backend, service_id, version, response.payload['detail'])) + + def get_director_name(self, service_id, version): + response = self._request('/service/%s/version/%s/director' % (service_id, version), 'GET') + if response.status == 200: + return response.payload + else: + raise Exception( + "Error retrieving director for service %s, version %s (%s)" % ( + service_id, version, response.payload['detail'])) + def create_director(self, service_id, version, director): response = self._request('/service/%s/version/%s/director' % (service_id, version), 'POST', director) if response.status != 200: @@ -807,6 +880,24 @@ def create_director(self, service_id, version, director): director.name, backend, service_id, version, response.payload['detail'])) return payload + def delete_director(self, service_id, version, director): + response = self._request('/service/%s/version/%s/director/%s' % (service_id, version, director), + 'DELETE') + if response.status == 200: + return response.payload + else: + raise Exception("Error deleting director %s service %s, version %s (%s)" % ( + director, service_id, version, response.payload['detail'])) + + def get_cache_settings_name(self, service_id, version): + response = self._request('/service/%s/version/%s/cache_settings' % (service_id, version), 'GET') + if response.status == 200: + return response.payload + else: + raise Exception( + "Error retrieving cache_settings for service %s, version %s (%s)" % ( + service_id, version, response.payload['detail'])) + def create_cache_settings(self, service_id, version, cache_settings): response = self._request('/service/%s/version/%s/cache_settings' % (service_id, version), 'POST', cache_settings) if response.status == 200: @@ -815,6 +906,23 @@ def create_cache_settings(self, service_id, version, cache_settings): raise Exception("Error creating cache_settings for service %s, version %s (%s)" % ( service_id, version, response.payload['detail'])) + def delete_cache_settings(self, service_id, version, cache_settings): + response = self._request('/service/%s/version/%s/backend/%s' % (service_id, version, cache_settings), + 'DELETE') + if response.status == 200: + return response.payload + else: + raise Exception("Error deleting cache_settings %s service %s, version %s (%s)" % ( + cache_settings, service_id, version, response.payload['detail'])) + + def get_condition_name(self, service_id, version): + response = self._request('/service/%s/version/%s/condition' % (service_id, version), 'GET') + if response.status == 200: + return response.payload + else: + raise Exception( + "Error retrieving condition for service %s, version %s (%s)" % (service_id, version, response.payload['detail'])) + def create_condition(self, service_id, version, condition): response = self._request('/service/%s/version/%s/condition' % (service_id, version), 'POST', condition) if response.status == 200: @@ -823,6 +931,24 @@ def create_condition(self, service_id, version, condition): raise Exception("Error creating condition for service %s, version %s (%s)" % ( service_id, version, response.payload['detail'])) + def delete_condition(self, service_id, version, condition): + response = self._request('/service/%s/version/%s/condition/%s' % (service_id, version, condition), + 'DELETE') + if response.status == 200: + return response.payload + else: + raise Exception("Error deleting condition %s service %s, version %s (%s)" % ( + condition, service_id, version, response.payload['detail'])) + + def get_gzip_name(self, service_id, version): + response = self._request('/service/%s/version/%s/gzip' % (service_id, version), 'GET') + if response.status == 200: + return response.payload + else: + raise Exception( + "Error retrieving gzip for service %s, version %s (%s)" % ( + service_id, version, response.payload['detail'])) + def create_gzip(self, service_id, version, gzip): response = self._request('/service/%s/version/%s/gzip' % (service_id, version), 'POST', gzip) @@ -832,6 +958,24 @@ def create_gzip(self, service_id, version, gzip): raise Exception("Error creating gzip for service %s, version %s (%s)" % ( service_id, version, response.payload['detail'])) + def delete_gzip(self, service_id, version, gzip): + response = self._request('/service/%s/version/%s/backend/%s' % (service_id, version, gzip), + 'DELETE') + if response.status == 200: + return response.payload + else: + raise Exception("Error deleting gzip %s service %s, version %s (%s)" % ( + gzip, service_id, version, response.payload['detail'])) + + def get_header_name(self, service_id, version): + response = self._request('/service/%s/version/%s/header' % (service_id, version), 'GET') + if response.status == 200: + return response.payload + else: + raise Exception( + "Error retrieving header for service %s, version %s (%s)" % ( + service_id, version, response.payload['detail'])) + def create_header(self, service_id, version, header): response = self._request('/service/%s/version/%s/header' % (service_id, version), 'POST', header) if response.status == 200: @@ -840,6 +984,24 @@ def create_header(self, service_id, version, header): raise Exception("Error creating header for service %s, version %s (%s)" % ( service_id, version, response.payload['detail'])) + def delete_header(self, service_id, version, header): + response = self._request('/service/%s/version/%s/header/%s' % (service_id, version, header), + 'DELETE') + if response.status == 200: + return response.payload + else: + raise Exception("Error deleting header %s service %s, version %s (%s)" % ( + header, service_id, version, response.payload['detail'])) + + def get_request_settings_name(self, service_id, version): + response = self._request('/service/%s/version/%s/request_settings' % (service_id, version), 'GET') + if response.status == 200: + return response.payload + else: + raise Exception( + "Error retrieving request_settings for service %s, version %s (%s)" % ( + service_id, version, response.payload['detail'])) + def create_request_setting(self, service_id, version, request_setting): response = self._request('/service/%s/version/%s/request_settings' % (service_id, version), 'POST', request_setting) @@ -849,6 +1011,24 @@ def create_request_setting(self, service_id, version, request_setting): raise Exception("Error creating request setting for service %s, version %s (%s)" % ( service_id, version, response.payload['detail'])) + def delete_request_settings(self, service_id, version, request_setting): + response = self._request('/service/%s/version/%s/request_settings/%s' % (service_id, version, request_setting), + 'DELETE') + if response.status == 200: + return response.payload + else: + raise Exception("Error deleting request_setting %s service %s, version %s (%s)" % ( + request_setting, service_id, version, response.payload['detail'])) + + def get_response_objects_name(self, service_id, version): + response = self._request('/service/%s/version/%s/response_object' % (service_id, version), 'GET') + if response.status == 200: + return response.payload + else: + raise Exception( + "Error retrieving response_object for service %s, version %s (%s)" % ( + service_id, version, response.payload['detail'])) + def create_response_object(self, service_id, version, response_object): response = self._request('/service/%s/version/%s/response_object' % (service_id, version), 'POST', response_object) @@ -858,6 +1038,24 @@ def create_response_object(self, service_id, version, response_object): raise Exception("Error creating response object for service %s, version %s (%s)" % ( service_id, version, response.payload['detail'])) + def delete_response_object(self, service_id, version, response_object): + response = self._request('/service/%s/version/%s/response_object/%s' % (service_id, version, response_object), + 'DELETE') + if response.status == 200: + return response.payload + else: + raise Exception("Error deleting response_object %s service %s, version %s (%s)" % ( + response_object, service_id, version, response.payload['detail'])) + + def get_vcl_name(self, service_id, version): + response = self._request('/service/%s/version/%s/vcl' % (service_id, version), 'GET') + if response.status == 200: + return response.payload + else: + raise Exception( + "Error retrieving vcl name for service %s, version %s (%s)" % ( + service_id, version, response.payload['detail'])) + def upload_custom_vcl(self, service_id, version, upload_vcl): response = self._request('/service/%s/version/%s/vcl' % (service_id, version), 'POST', upload_vcl) @@ -870,6 +1068,24 @@ def upload_custom_vcl(self, service_id, version, upload_vcl): else: raise Exception("Error uploading VCL '%s' for service %s, version %s (%s)" % (upload_vcl['name'], service_id, version, response.payload['detail'])) + def delete_vcl(self, service_id, version, vcl): + response = self._request('/service/%s/version/%s/vcl/%s' % (service_id, version, vcl), + 'DELETE') + if response.status == 200: + return response.payload + else: + raise Exception("Error deleting vcl %s service %s, version %s (%s)" % ( + vcl, service_id, version, response.payload['detail'])) + + def get_vcl_snippet_name(self, service_id, version): + response = self._request('/service/%s/version/%s/snippet' % (service_id, version), 'GET') + if response.status == 200: + return response.payload + else: + raise Exception( + "Error retrieving vcl snippt for service %s, version %s (%s)" % ( + service_id, version, response.payload['detail'])) + def create_vcl_snippet(self, service_id, version, vcl_snippet): response = self._request('/service/%s/version/%s/snippet' % (service_id, version), 'POST', vcl_snippet) @@ -878,6 +1094,23 @@ def create_vcl_snippet(self, service_id, version, vcl_snippet): else: raise Exception("Error creating VCL snippet '%s' for service %s, version %s (%s)" % (vcl_snippet['name'], service_id, version, response.payload['detail'])) + def delete_vcl_snippet(self, service_id, version, snippet): + response = self._request('/service/%s/version/%s/snippet/%s' % (service_id, version, snippet), + 'DELETE') + if response.status == 200: + return response.payload + else: + raise Exception("Error deleting vcl snippet %s service %s, version %s (%s)" % ( + snippet, service_id, version, response.payload['detail'])) + + def get_sysloglogs_name(self, service_id, version): + response = self._request('/service/%s/version/%s/syslog' % (service_id, version), 'GET') + if response.status == 200: + return response.payload + else: + raise Exception( + "Error retrieving syslog name for service %s, version %s (%s)" % ( + service_id, version, response.payload['detail'])) def create_sysloglogs(self, service_id, version, create_syslog): response = self._request('/service/%s/version/%s/logging/syslog' % (service_id, version), 'POST', create_syslog) @@ -887,6 +1120,14 @@ def create_sysloglogs(self, service_id, version, create_syslog): else: raise Exception("Error creating syslog log '%s' for service %s, version %s (%s)" % (create_syslog['name'], service_id, version, response.payload['detail'])) + def delete_sysloglogs(self, service_id, version, syslog): + response = self._request('/service/%s/version/%s/syslog/%s' % (service_id, version, syslog), + 'DELETE') + if response.status == 200: + return response.payload + else: + raise Exception("Error deleting syslog %s service %s, version %s (%s)" % ( + syslog, service_id, version, response.payload['detail'])) def create_settings(self, service_id, version, settings): response = self._request('/service/%s/version/%s/settings' % (service_id, version), 'PUT', settings) @@ -911,7 +1152,8 @@ def __init__(self, client): def apply_configuration(self, service_name, fastly_configuration, activate_new_version=True): actions = [] - + clone = False + version_number = "" service = self.client.get_service_by_name(service_name) if service is None: @@ -924,19 +1166,90 @@ def apply_configuration(self, service_name, fastly_configuration, activate_new_v current_version = service.latest_version if current_version is None: - self.deploy_version_with_configuration(service.id, fastly_configuration, activate_new_version) + self.deploy_version_with_configuration(service.id, fastly_configuration, + activate_new_version) actions.append("Deployed new version because service has no active version") elif fastly_configuration != current_version.configuration: - self.deploy_version_with_configuration(service.id, fastly_configuration, activate_new_version) + version_number = self.clone_old_version(service.id) + clone = True + self.delete_version_before_apply_config(service.id, version_number, fastly_configuration) + self.deploy_version_with_configuration(service.id, fastly_configuration, + activate_new_version, clone, version_number) actions.append("Deployed new version because settings are not up to date") changed = len(actions) > 0 service = self.client.get_service(service.id) return FastlyStateEnforcerResult(actions=actions, changed=changed, service=service) - def deploy_version_with_configuration(self, service_id, configuration, activate_version): - version = self.client.create_version(service_id) - version_number = version['number'] + def clone_old_version(self, service_id): + version_to_clone = self.client.get_active_version(service_id) + clone = self.client.clone_old_version(service_id, version_to_clone) + clone_version_number = clone['number'] + return clone_version_number + + def delete_version_before_apply_config(self, service_id, version_to_delete, configuration): + + domain = self.client.get_domain_name(service_id, version_to_delete) + healthcheck = self.client.get_healthcheck_name(service_id, version_to_delete) + condition = self.client.get_condition_name(service_id, version_to_delete) + backend = self.client.get_backend_name(service_id, version_to_delete) + director = self.client.get_director_name(service_id, version_to_delete) + cache_settings = self.client.get_cache_settings_name(service_id, version_to_delete) + gzips = self.client.get_gzip_name(service_id, version_to_delete) + headers = self.client.get_header_name(service_id, version_to_delete) + request_settings = self.client.get_request_settings_name(service_id, version_to_delete) + response_objects = self.client.get_response_objects_name(service_id, version_to_delete) + vcl = self.client.get_vcl_name(service_id, version_to_delete) + snippets = self.client.get_vcl_snippet_name(service_id, version_to_delete) + sysloglogs = self.client.get_sysloglogs_name(service_id, version_to_delete) + + for domain_name in domain: + self.client.delete_domain(service_id, version_to_delete, domain_name['name']) + + for healthcheck_name in healthcheck: + self.client.delete_healthcheck(service_id, version_to_delete, healthcheck_name['name']) + + for condition_name in condition: + self.client.delete_condition(service_id, version_to_delete, condition_name['name']) + + for backend_name in backend: + self.client.delete_backend(service_id, version_to_delete, backend_name['name']) + + for director_name in director: + self.client.delete_backend(service_id, version_to_delete, director_name['name']) + + for cache_settings_name in cache_settings: + self.client.delete_cache_settings(service_id, version_to_delete, cache_settings_name['name']) + + for gzip_name in gzips: + self.client.delete_gzip(service_id, version_to_delete, gzip_name['name']) + + for header_name in headers: + self.client.delete_header(service_id, version_to_delete, header_name['name']) + + for request_setting_name in request_settings: + self.client.delete_request_settings(service_id, version_to_delete, request_setting_name['name']) + + for response_object_name in response_objects: + self.client.delete_response_object(service_id, version_to_delete, response_object_name['name']) + + for custom_vcl_name in vcl: + self.client.delete_vcl(service_id, version_to_delete, custom_vcl_name['name']) + + for vcl_snippet_name in snippets: + self.client.delete_vcl_snippet(service_id, version_to_delete, vcl_snippet_name['name']) + + for syslog_name in sysloglogs: + self.client.delete_sysloglogs(service_id, version_to_delete, syslog_name['name']) + + def deploy_version_with_configuration(self, service_id, configuration, activate_version, + clone=False, cloned_version=""): + + if clone: + version_number = cloned_version + else: + version = self.client.create_version(service_id) + version_number = version['number'] for domain in configuration.domains: self.client.create_domain(service_id, version_number, domain) @@ -1088,4 +1401,4 @@ def main(): if __name__ == '__main__': - main() \ No newline at end of file + main() From 07eb558d59a4318f27b4850d68e8bae70734bbc1 Mon Sep 17 00:00:00 2001 From: joaopereiramrf Date: Sun, 18 Feb 2018 17:47:19 +0100 Subject: [PATCH 05/13] remove some variables --- library/fastly_service.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/fastly_service.py b/library/fastly_service.py index dc28e5b..e3f1b9a 100644 --- a/library/fastly_service.py +++ b/library/fastly_service.py @@ -1152,8 +1152,6 @@ def __init__(self, client): def apply_configuration(self, service_name, fastly_configuration, activate_new_version=True): actions = [] - clone = False - version_number = "" service = self.client.get_service_by_name(service_name) if service is None: @@ -1243,11 +1241,9 @@ def delete_version_before_apply_config(self, service_id, version_to_delete, conf self.client.delete_sysloglogs(service_id, version_to_delete, syslog_name['name']) def deploy_version_with_configuration(self, service_id, configuration, activate_version, - clone=False, cloned_version=""): + clone=False, version_number=""): - if clone: - version_number = cloned_version - else: + if not clone: version = self.client.create_version(service_id) version_number = version['number'] From e98bc0d9bca703bcc188de08638caca60c1d9743 Mon Sep 17 00:00:00 2001 From: joaopereiramrf Date: Mon, 19 Feb 2018 14:02:45 +0100 Subject: [PATCH 06/13] rename methods and syslog class --- library/fastly_service.py | 91 +++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/library/fastly_service.py b/library/fastly_service.py index e3f1b9a..aa82fea 100644 --- a/library/fastly_service.py +++ b/library/fastly_service.py @@ -530,7 +530,7 @@ def __init__(self, config, validate_choices): def sort_key(f): return f.name -class FastlySysloglogs(FastlyObject): +class Fastlysyslog(FastlyObject): schema = { 'name': dict(required=True, type='str', default=None), 'format': dict(required=True, type='str', default=None), @@ -584,7 +584,7 @@ def __init__(self, configuration, validate_choices=True): self.request_settings = [] self.uploads = [] self.snippets = [] - self.sysloglogs = [] + self.syslog = [] self.settings = FastlySettings(dict(), validate_choices) if 'domains' in configuration and configuration['domains'] is not None: @@ -635,9 +635,9 @@ def __init__(self, configuration, validate_choices=True): for snippet in configuration['snippets']: self.snippets.append(FastlyVclSnippet(snippet, validate_choices)) - if 'sysloglogs' in configuration and configuration['sysloglogs'] is not None: - for sysloglog in configuration['sysloglogs']: - self.sysloglogs.append(FastlySysloglogs(sysloglog, validate_choices)) + if 'syslog' in configuration and configuration['syslog'] is not None: + for sysloglog in configuration['syslog']: + self.syslog.append(Fastlysyslog(sysloglog, validate_choices)) if 'settings' in configuration and configuration['settings'] is not None: self.settings = FastlySettings(configuration['settings'], validate_choices) @@ -655,7 +655,7 @@ def __eq__(self, other): and sorted(self.response_objects, key=FastlyResponseObject.sort_key) == sorted(other.response_objects, key=FastlyResponseObject.sort_key) \ and sorted(self.uploads, key=FastlyVclUpload.sort_key) == sorted(other.uploads, key=FastlyVclUpload.sort_key) \ and sorted(self.snippets, key=FastlyVclSnippet.sort_key) == sorted(other.snippets, key=FastlyVclSnippet.sort_key) \ - and sorted(self.sysloglogs, key=FastlySysloglogs.sort_key) == sorted(other.sysloglogs, key=FastlySysloglogs.sort_key) \ + and sorted(self.syslog, key=Fastlysyslog.sort_key) == sorted(other.syslog, key=Fastlysyslog.sort_key) \ and self.settings == other.settings def __ne__(self, other): @@ -781,7 +781,7 @@ def deactivate_version(self, service_id, version): raise Exception( "Error deactivating version %s for service %s (%s)" % (version, service_id, response.payload['detail'])) - def get_domain_name(self, service_id, version): + def get_domain(self, service_id, version): response = self._request('/service/%s/version/%s/domain' % (service_id, version), 'GET') if response.status == 200: return response.payload @@ -805,7 +805,7 @@ def delete_domain(self, service_id, version, domain): else: raise Exception("Error deleting domain %s service %s, version %s (%s)" % (domain, service_id, version, response.payload['detail'])) - def get_healthcheck_name(self, service_id, version): + def get_healthcheck(self, service_id, version): response = self._request('/service/%s/version/%s/healthcheck' % (service_id, version), 'GET') if response.status == 200: return response.payload @@ -830,7 +830,7 @@ def delete_healthcheck(self, service_id, version, healthcheck): raise Exception("Error deleting healthcheck %s service %s, version %s (%s)" % ( healthcheck, service_id, version, response.payload['detail'])) - def get_backend_name(self, service_id, version): + def get_backend(self, service_id, version): response = self._request('/service/%s/version/%s/backend' % (service_id, version), 'GET') if response.status == 200: return response.payload @@ -856,7 +856,7 @@ def delete_backend(self, service_id, version, backend): raise Exception("Error deleting backend %s service %s, version %s (%s)" % ( backend, service_id, version, response.payload['detail'])) - def get_director_name(self, service_id, version): + def get_director(self, service_id, version): response = self._request('/service/%s/version/%s/director' % (service_id, version), 'GET') if response.status == 200: return response.payload @@ -889,7 +889,7 @@ def delete_director(self, service_id, version, director): raise Exception("Error deleting director %s service %s, version %s (%s)" % ( director, service_id, version, response.payload['detail'])) - def get_cache_settings_name(self, service_id, version): + def get_cache_settings(self, service_id, version): response = self._request('/service/%s/version/%s/cache_settings' % (service_id, version), 'GET') if response.status == 200: return response.payload @@ -915,7 +915,7 @@ def delete_cache_settings(self, service_id, version, cache_settings): raise Exception("Error deleting cache_settings %s service %s, version %s (%s)" % ( cache_settings, service_id, version, response.payload['detail'])) - def get_condition_name(self, service_id, version): + def get_condition(self, service_id, version): response = self._request('/service/%s/version/%s/condition' % (service_id, version), 'GET') if response.status == 200: return response.payload @@ -940,7 +940,7 @@ def delete_condition(self, service_id, version, condition): raise Exception("Error deleting condition %s service %s, version %s (%s)" % ( condition, service_id, version, response.payload['detail'])) - def get_gzip_name(self, service_id, version): + def get_gzip(self, service_id, version): response = self._request('/service/%s/version/%s/gzip' % (service_id, version), 'GET') if response.status == 200: return response.payload @@ -967,7 +967,7 @@ def delete_gzip(self, service_id, version, gzip): raise Exception("Error deleting gzip %s service %s, version %s (%s)" % ( gzip, service_id, version, response.payload['detail'])) - def get_header_name(self, service_id, version): + def get_header(self, service_id, version): response = self._request('/service/%s/version/%s/header' % (service_id, version), 'GET') if response.status == 200: return response.payload @@ -993,7 +993,7 @@ def delete_header(self, service_id, version, header): raise Exception("Error deleting header %s service %s, version %s (%s)" % ( header, service_id, version, response.payload['detail'])) - def get_request_settings_name(self, service_id, version): + def get_request_setting(self, service_id, version): response = self._request('/service/%s/version/%s/request_settings' % (service_id, version), 'GET') if response.status == 200: return response.payload @@ -1011,7 +1011,7 @@ def create_request_setting(self, service_id, version, request_setting): raise Exception("Error creating request setting for service %s, version %s (%s)" % ( service_id, version, response.payload['detail'])) - def delete_request_settings(self, service_id, version, request_setting): + def delete_request_setting(self, service_id, version, request_setting): response = self._request('/service/%s/version/%s/request_settings/%s' % (service_id, version, request_setting), 'DELETE') if response.status == 200: @@ -1020,7 +1020,7 @@ def delete_request_settings(self, service_id, version, request_setting): raise Exception("Error deleting request_setting %s service %s, version %s (%s)" % ( request_setting, service_id, version, response.payload['detail'])) - def get_response_objects_name(self, service_id, version): + def get_response_object(self, service_id, version): response = self._request('/service/%s/version/%s/response_object' % (service_id, version), 'GET') if response.status == 200: return response.payload @@ -1047,7 +1047,7 @@ def delete_response_object(self, service_id, version, response_object): raise Exception("Error deleting response_object %s service %s, version %s (%s)" % ( response_object, service_id, version, response.payload['detail'])) - def get_vcl_name(self, service_id, version): + def get_custom_vcl(self, service_id, version): response = self._request('/service/%s/version/%s/vcl' % (service_id, version), 'GET') if response.status == 200: return response.payload @@ -1068,7 +1068,7 @@ def upload_custom_vcl(self, service_id, version, upload_vcl): else: raise Exception("Error uploading VCL '%s' for service %s, version %s (%s)" % (upload_vcl['name'], service_id, version, response.payload['detail'])) - def delete_vcl(self, service_id, version, vcl): + def delete_custom_vcl(self, service_id, version, vcl): response = self._request('/service/%s/version/%s/vcl/%s' % (service_id, version, vcl), 'DELETE') if response.status == 200: @@ -1077,7 +1077,7 @@ def delete_vcl(self, service_id, version, vcl): raise Exception("Error deleting vcl %s service %s, version %s (%s)" % ( vcl, service_id, version, response.payload['detail'])) - def get_vcl_snippet_name(self, service_id, version): + def get_vcl_snippet(self, service_id, version): response = self._request('/service/%s/version/%s/snippet' % (service_id, version), 'GET') if response.status == 200: return response.payload @@ -1103,7 +1103,7 @@ def delete_vcl_snippet(self, service_id, version, snippet): raise Exception("Error deleting vcl snippet %s service %s, version %s (%s)" % ( snippet, service_id, version, response.payload['detail'])) - def get_sysloglogs_name(self, service_id, version): + def get_syslog(self, service_id, version): response = self._request('/service/%s/version/%s/syslog' % (service_id, version), 'GET') if response.status == 200: return response.payload @@ -1112,7 +1112,7 @@ def get_sysloglogs_name(self, service_id, version): "Error retrieving syslog name for service %s, version %s (%s)" % ( service_id, version, response.payload['detail'])) - def create_sysloglogs(self, service_id, version, create_syslog): + def create_syslog(self, service_id, version, create_syslog): response = self._request('/service/%s/version/%s/logging/syslog' % (service_id, version), 'POST', create_syslog) if response.status == 200: @@ -1120,7 +1120,7 @@ def create_sysloglogs(self, service_id, version, create_syslog): else: raise Exception("Error creating syslog log '%s' for service %s, version %s (%s)" % (create_syslog['name'], service_id, version, response.payload['detail'])) - def delete_sysloglogs(self, service_id, version, syslog): + def delete_syslog(self, service_id, version, syslog): response = self._request('/service/%s/version/%s/syslog/%s' % (service_id, version, syslog), 'DELETE') if response.status == 200: @@ -1169,10 +1169,9 @@ def apply_configuration(self, service_name, fastly_configuration, activate_new_v actions.append("Deployed new version because service has no active version") elif fastly_configuration != current_version.configuration: version_number = self.clone_old_version(service.id) - clone = True self.delete_version_before_apply_config(service.id, version_number, fastly_configuration) self.deploy_version_with_configuration(service.id, fastly_configuration, - activate_new_version, clone, version_number) + activate_new_version, True, version_number) actions.append("Deployed new version because settings are not up to date") changed = len(actions) > 0 @@ -1187,19 +1186,19 @@ def clone_old_version(self, service_id): def delete_version_before_apply_config(self, service_id, version_to_delete, configuration): - domain = self.client.get_domain_name(service_id, version_to_delete) - healthcheck = self.client.get_healthcheck_name(service_id, version_to_delete) - condition = self.client.get_condition_name(service_id, version_to_delete) - backend = self.client.get_backend_name(service_id, version_to_delete) - director = self.client.get_director_name(service_id, version_to_delete) - cache_settings = self.client.get_cache_settings_name(service_id, version_to_delete) - gzips = self.client.get_gzip_name(service_id, version_to_delete) - headers = self.client.get_header_name(service_id, version_to_delete) - request_settings = self.client.get_request_settings_name(service_id, version_to_delete) - response_objects = self.client.get_response_objects_name(service_id, version_to_delete) - vcl = self.client.get_vcl_name(service_id, version_to_delete) - snippets = self.client.get_vcl_snippet_name(service_id, version_to_delete) - sysloglogs = self.client.get_sysloglogs_name(service_id, version_to_delete) + domain = self.client.get_domain(service_id, version_to_delete) + healthcheck = self.client.get_healthcheck(service_id, version_to_delete) + condition = self.client.get_condition(service_id, version_to_delete) + backend = self.client.get_backend(service_id, version_to_delete) + director = self.client.get_director(service_id, version_to_delete) + cache_settings = self.client.get_cache_settings(service_id, version_to_delete) + gzips = self.client.get_gzip(service_id, version_to_delete) + headers = self.client.get_header(service_id, version_to_delete) + request_settings = self.client.get_request_setting(service_id, version_to_delete) + response_objects = self.client.get_response_object(service_id, version_to_delete) + vcl = self.client.get_custom_vcl(service_id, version_to_delete) + snippets = self.client.get_vcl_snippet(service_id, version_to_delete) + syslog = self.client.get_syslog(service_id, version_to_delete) for domain_name in domain: self.client.delete_domain(service_id, version_to_delete, domain_name['name']) @@ -1217,7 +1216,7 @@ def delete_version_before_apply_config(self, service_id, version_to_delete, conf self.client.delete_backend(service_id, version_to_delete, director_name['name']) for cache_settings_name in cache_settings: - self.client.delete_cache_settings(service_id, version_to_delete, cache_settings_name['name']) + self.client.delete_cache_setting(service_id, version_to_delete, cache_settings_name['name']) for gzip_name in gzips: self.client.delete_gzip(service_id, version_to_delete, gzip_name['name']) @@ -1226,19 +1225,19 @@ def delete_version_before_apply_config(self, service_id, version_to_delete, conf self.client.delete_header(service_id, version_to_delete, header_name['name']) for request_setting_name in request_settings: - self.client.delete_request_settings(service_id, version_to_delete, request_setting_name['name']) + self.client.delete_request_setting(service_id, version_to_delete, request_setting_name['name']) for response_object_name in response_objects: self.client.delete_response_object(service_id, version_to_delete, response_object_name['name']) for custom_vcl_name in vcl: - self.client.delete_vcl(service_id, version_to_delete, custom_vcl_name['name']) + self.client.delete_custom_vcl(service_id, version_to_delete, custom_vcl_name['name']) for vcl_snippet_name in snippets: self.client.delete_vcl_snippet(service_id, version_to_delete, vcl_snippet_name['name']) - for syslog_name in sysloglogs: - self.client.delete_sysloglogs(service_id, version_to_delete, syslog_name['name']) + for syslog_name in syslog: + self.client.delete_syslog(service_id, version_to_delete, syslog_name['name']) def deploy_version_with_configuration(self, service_id, configuration, activate_version, clone=False, version_number=""): @@ -1286,8 +1285,8 @@ def deploy_version_with_configuration(self, service_id, configuration, activate_ for vcl_snippet in configuration.snippets: self.client.create_vcl_snippet(service_id, version_number, vcl_snippet) - for create_syslog in configuration.sysloglogs: - self.client.create_sysloglogs(service_id, version_number, create_syslog) + for create_syslog in configuration.syslog: + self.client.create_syslog(service_id, version_number, create_syslog) if configuration.settings: self.client.create_settings(service_id, version_number, configuration.settings) @@ -1361,7 +1360,7 @@ def configuration(self): 'response_objects': self.module.params['response_objects'], 'uploads': self.module.params['upload_vcls'], 'snippets': self.module.params['vcl_snippets'], - 'sysloglogs': self.module.params['create_syslogs'], + 'syslog': self.module.params['create_syslogs'], 'settings': self.module.params['settings'] }) except FastlyValidationError as err: From bcb0605bb85902f8b73244b18485456ee97ffd68 Mon Sep 17 00:00:00 2001 From: joaopereiramrf Date: Mon, 5 Mar 2018 16:11:38 +0100 Subject: [PATCH 07/13] ignore null values for multi domains --- library/fastly_service.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/fastly_service.py b/library/fastly_service.py index aa82fea..27cd020 100644 --- a/library/fastly_service.py +++ b/library/fastly_service.py @@ -589,7 +589,8 @@ def __init__(self, configuration, validate_choices=True): if 'domains' in configuration and configuration['domains'] is not None: for domain in configuration['domains']: - self.domains.append(FastlyDomain(domain, validate_choices)) + if domain['name']: + self.domains.append(FastlyDomain(domain, validate_choices)) if 'healthchecks' in configuration and configuration['healthchecks'] is not None: for healthcheck in configuration['healthchecks']: From ce4542715f4fa56ac29d03055022654ba5aca035 Mon Sep 17 00:00:00 2001 From: joaopereiramrf Date: Tue, 13 Mar 2018 10:30:54 +0100 Subject: [PATCH 08/13] add option ssl_check_cert --- library/fastly_service.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/fastly_service.py b/library/fastly_service.py index 27cd020..5a630e0 100644 --- a/library/fastly_service.py +++ b/library/fastly_service.py @@ -252,6 +252,7 @@ class FastlyBackend(FastlyObject): 'ssl_ca_cert': dict(required=False, type='str', default=None, exclude_empty_str=True), 'ssl_cert_hostname': dict(required=False, type='str', default=None, exclude_empty_str=True), 'ssl_sni_hostname': dict(required=False, type='str', default=None, exclude_empty_str=True), + 'ssl_check_cert': dict(required=False, type='str', default=None, exclude_empty_str=True), 'min_tls_version': dict(required=False, type='str', default=None, exclude_empty_str=True), 'max_tls_version': dict(required=False, type='str', default=None, exclude_empty_str=True), 'shield': dict(required=False, type='str', default=None, exclude_empty_str=True), @@ -273,6 +274,7 @@ def __init__(self, config, validate_choices): self.ssl_ca_cert = self.read_config(config, validate_choices, 'ssl_ca_cert') self.ssl_cert_hostname = self.read_config(config, validate_choices, 'ssl_cert_hostname') self.ssl_sni_hostname = self.read_config(config, validate_choices, 'ssl_sni_hostname') + self.ssl_check_cert = self.read_config(config, validate_choices, 'ssl_check_cert') self.min_tls_version = self.read_config(config, validate_choices, 'min_tls_version') self.max_tls_version = self.read_config(config, validate_choices, 'max_tls_version') self.shield = self.read_config(config, validate_choices, 'shield') From 74b997c5072fbcd6fab10537811edbe3122519db Mon Sep 17 00:00:00 2001 From: joaopereiramrf Date: Tue, 13 Mar 2018 10:51:33 +0100 Subject: [PATCH 09/13] replace str by int --- library/fastly_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/fastly_service.py b/library/fastly_service.py index 5a630e0..a8053f8 100644 --- a/library/fastly_service.py +++ b/library/fastly_service.py @@ -252,7 +252,7 @@ class FastlyBackend(FastlyObject): 'ssl_ca_cert': dict(required=False, type='str', default=None, exclude_empty_str=True), 'ssl_cert_hostname': dict(required=False, type='str', default=None, exclude_empty_str=True), 'ssl_sni_hostname': dict(required=False, type='str', default=None, exclude_empty_str=True), - 'ssl_check_cert': dict(required=False, type='str', default=None, exclude_empty_str=True), + 'ssl_check_cert': dict(required=False, type='int', default=None), 'min_tls_version': dict(required=False, type='str', default=None, exclude_empty_str=True), 'max_tls_version': dict(required=False, type='str', default=None, exclude_empty_str=True), 'shield': dict(required=False, type='str', default=None, exclude_empty_str=True), From 596b51333df002059cb96663ce144d1c4484a3fe Mon Sep 17 00:00:00 2001 From: joaopereiramrf Date: Sat, 13 Oct 2018 16:31:50 +0200 Subject: [PATCH 10/13] upload custom vcl --- library/fastly_service.py | 45 +++++++------- tests/test_fastly_vcls.py | 123 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 22 deletions(-) create mode 100644 tests/test_fastly_vcls.py diff --git a/library/fastly_service.py b/library/fastly_service.py index f071530..ac41bc1 100644 --- a/library/fastly_service.py +++ b/library/fastly_service.py @@ -70,7 +70,7 @@ required: false description: - List of Syslog loggers - upload_vcls: + vcls: required: false description: - Upload VCL @@ -426,11 +426,11 @@ def sort_key(f): class FastlyHealthcheck(FastlyObject): schema = { - 'name': dict(required=True, type='str', default=None), + 'name': dict(required=False, type='str', default=None), 'check_interval': dict(required=False, type='int', default=None), 'comment': dict(required=False, type='str', default=''), 'expected_response': dict(required=False, type='int', default=200), - 'host': dict(required=True, type='str', default=None), + 'host': dict(required=False, type='str', default=None), 'http_version': dict(required=False, type='str', default='1.1'), 'initial': dict(required=False, type='int', default=None), 'method': dict(required=False, type='str', default='HEAD'), @@ -656,7 +656,7 @@ def __init__(self, cfg, validate_choices=True): self.headers = [FastlyHeader(h, validate_choices) for h in cfg.get('headers') or []] self.response_objects = [FastlyResponseObject(r, validate_choices) for r in cfg.get('response_objects') or []] self.request_settings = [FastlyRequestSetting(r, validate_choices) for r in cfg.get('request_settings') or []] - self.uploads = [] + self.custom_vcls = [] self.snippets = [FastlyVclSnippet(s, validate_choices) for s in cfg.get('snippets') or []] self.s3s = [FastlyS3Logging(s, validate_choices) for s in cfg.get('s3s') or []] self.syslogs = [FastlySyslogLogging(s, validate_choices) for s in cfg.get('syslogs') or []] @@ -664,20 +664,20 @@ def __init__(self, cfg, validate_choices=True): def __eq__(self, other): return sorted(self.domains, key=FastlyDomain.sort_key) == sorted(other.domains, key=FastlyDomain.sort_key) \ - and sorted(self.healthchecks, key=FastlyHealthcheck.sort_key) == sorted(other.healthchecks, key=FastlyHealthcheck.sort_key) \ - and sorted(self.backends, key=FastlyBackend.sort_key) == sorted(other.backends, key=FastlyBackend.sort_key) \ - and sorted(self.cache_settings, key=FastlyCacheSettings.sort_key) == sorted(other.cache_settings, key=FastlyCacheSettings.sort_key) \ - and sorted(self.conditions, key=FastlyCondition.sort_key) == sorted(other.conditions, key=FastlyCondition.sort_key) \ - and sorted(self.directors, key=FastlyDirector.sort_key) == sorted(other.directors, key=FastlyDirector.sort_key) \ - and sorted(self.gzips, key=FastlyGzip.sort_key) == sorted(other.gzips, key=FastlyGzip.sort_key) \ - and sorted(self.headers, key=FastlyHeader.sort_key) == sorted(other.headers, key=FastlyHeader.sort_key) \ - and sorted(self.request_settings, key=FastlyRequestSetting.sort_key) == sorted(other.request_settings, key=FastlyRequestSetting.sort_key) \ - and sorted(self.response_objects, key=FastlyResponseObject.sort_key) == sorted(other.response_objects, key=FastlyResponseObject.sort_key) \ - and sorted(self.uploads, key=FastlyVclUpload.sort_key) == sorted(other.uploads, key=FastlyVclUpload.sort_key) \ - and sorted(self.snippets, key=FastlyVclSnippet.sort_key) == sorted(other.snippets, key=FastlyVclSnippet.sort_key) \ - and sorted(self.s3s, key=FastlyS3Logging.sort_key) == sorted(other.s3s, key=FastlyS3Logging.sort_key) \ - and sorted(self.syslogs, key=FastlySyslogLogging.sort_key) == sorted(other.syslogs, key=FastlySyslogLogging.sort_key) \ - and self.settings == other.settings + and sorted(self.healthchecks, key=FastlyHealthcheck.sort_key) == sorted(other.healthchecks, key=FastlyHealthcheck.sort_key) \ + and sorted(self.backends, key=FastlyBackend.sort_key) == sorted(other.backends, key=FastlyBackend.sort_key) \ + and sorted(self.cache_settings, key=FastlyCacheSettings.sort_key) == sorted(other.cache_settings, key=FastlyCacheSettings.sort_key) \ + and sorted(self.conditions, key=FastlyCondition.sort_key) == sorted(other.conditions, key=FastlyCondition.sort_key) \ + and sorted(self.directors, key=FastlyDirector.sort_key) == sorted(other.directors, key=FastlyDirector.sort_key) \ + and sorted(self.gzips, key=FastlyGzip.sort_key) == sorted(other.gzips, key=FastlyGzip.sort_key) \ + and sorted(self.headers, key=FastlyHeader.sort_key) == sorted(other.headers, key=FastlyHeader.sort_key) \ + and sorted(self.request_settings, key=FastlyRequestSetting.sort_key) == sorted(other.request_settings, key=FastlyRequestSetting.sort_key) \ + and sorted(self.response_objects, key=FastlyResponseObject.sort_key) == sorted(other.response_objects, key=FastlyResponseObject.sort_key) \ + and sorted(self.custom_vcls, key=FastlyVclUpload.sort_key) == sorted(other.custom_vcls, key=FastlyVclUpload.sort_key) \ + and sorted(self.snippets, key=FastlyVclSnippet.sort_key) == sorted(other.snippets, key=FastlyVclSnippet.sort_key) \ + and sorted(self.s3s, key=FastlyS3Logging.sort_key) == sorted(other.s3s, key=FastlyS3Logging.sort_key) \ + and sorted(self.syslogs, key=FastlySyslogLogging.sort_key) == sorted(other.syslogs, key=FastlySyslogLogging.sort_key) \ + and self.settings == other.settings def __ne__(self, other): return not self.__eq__(other) @@ -1243,7 +1243,8 @@ def configure_version(self, service_id, configuration, version_number): # create healthchecks before backends for healthcheck in configuration.healthchecks: - self.client.create_healthcheck(service_id, version_number, healthcheck) + if healthcheck.name: + self.client.create_healthcheck(service_id, version_number, healthcheck) # create conditions before dependencies (e.g. cache_settings) for condition in configuration.conditions: @@ -1271,7 +1272,7 @@ def configure_version(self, service_id, configuration, version_number): for response_object in configuration.response_objects: self.client.create_response_object(service_id, version_number, response_object) - for upload_vcl in configuration.uploads: + for upload_vcl in configuration.custom_vcls: self.client.upload_custom_vcl(service_id, version_number, upload_vcl) for vcl_snippet in configuration.snippets: @@ -1320,7 +1321,7 @@ def __init__(self): headers=dict(default=None, required=False, type='list'), request_settings=dict(default=None, required=False, type='list'), response_objects=dict(default=None, required=False, type='list'), - upload_vcls=dict(default=None, required=False, type='list'), + vcls=dict(default=None, required=False, type='list'), vcl_snippets=dict(default=None, required=False, type='list'), s3s=dict(default=None, required=False, type='list'), syslogs=dict(default=None, required=False, type='list'), @@ -1351,7 +1352,7 @@ def configuration(self): 'headers': self.module.params['headers'], 'request_settings': self.module.params['request_settings'], 'response_objects': self.module.params['response_objects'], - 'uploads': self.module.params['upload_vcls'], + 'custom_vcls': self.module.params['vcls'], 'snippets': self.module.params['vcl_snippets'], 's3s': self.module.params['s3s'], 'syslogs': self.module.params['syslogs'], diff --git a/tests/test_fastly_vcls.py b/tests/test_fastly_vcls.py new file mode 100644 index 0000000..e5f4571 --- /dev/null +++ b/tests/test_fastly_vcls.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python +import os +import unittest +import sys + +from test_common import TestCommon + +sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'library')) +from fastly_service import FastlyConfiguration + +class TestFastlyVclSnippets(TestCommon): + + VCLS_NAME = 'Main.vcl'; + + @TestCommon.vcr.use_cassette() + def test_fastly_vcl_main(self): + content = ''' + sub vcl_recv { + #FASTLY recv + + if (req.method != "HEAD" && req.method != "GET" && req.method != "FASTLYPURGE") { + return(pass); + } + + return(lookup); + } + + sub vcl_fetch { + #FASTLY fetch + + if ((beresp.status == 500 || beresp.status == 503) && req.restarts < 1 && (req.method == "GET" || req.method == "HEAD")) { + restart; + } + + if (req.restarts > 0) { + set beresp.http.Fastly-Restarts = req.restarts; + } + + if (beresp.http.Set-Cookie) { + set req.http.Fastly-Cachetype = "SETCOOKIE"; + return(pass); + } + + if (beresp.http.Cache-Control ~ "private") { + set req.http.Fastly-Cachetype = "PRIVATE"; + return(pass); + } + + if (beresp.status == 500 || beresp.status == 503) { + set req.http.Fastly-Cachetype = "ERROR"; + set beresp.ttl = 1s; + set beresp.grace = 5s; + return(deliver); + } + + if (beresp.http.Expires || beresp.http.Surrogate-Control ~ "max-age" || beresp.http.Cache-Control ~ "(s-maxage|max-age)") { + # keep the ttl here + } else { + # apply the default ttl + set beresp.ttl = 3600s; + } + + return(deliver); + } + + sub vcl_hit { + #FASTLY hit + + if (!obj.cacheable) { + return(pass); + } + return(deliver); + } + + sub vcl_miss { + #FASTLY miss + return(fetch); + } + + sub vcl_deliver { + #FASTLY deliver + return(deliver); + } + + sub vcl_error { + #FASTLY error + } + + sub vcl_pass { + #FASTLY pass + } + + sub vcl_log { + #FASTLY log + } + ''' + + vcls_configuration = self.minimal_configuration.copy() + vcls_configuration.update({ + 'snippets': [{ + 'name': self.VCLS_NAME, + 'dynamic': 0, + 'type': 'deliver', + 'content': content, + }] + }) + + configuration = FastlyConfiguration(vcls_configuration) + service = self.enforcer.apply_configuration(self.FASTLY_TEST_SERVICE, configuration).service + + self.assertEqual(service.active_version.configuration.vcls[0].name, self.VCLS_NAME) + self.assertEqual(service.active_version.configuration.vcls[0].dynamic, 0) + self.assertEqual(service.active_version.configuration.vcls[0].type, 'deliver') + self.assertEqual(service.active_version.configuration.vcls[0].content, content) + self.assertEqual(service.active_version.configuration, configuration) + + active_version_number = service.active_version.number + service = self.enforcer.apply_configuration(self.FASTLY_TEST_SERVICE, configuration).service + self.assertEqual(service.active_version.number, active_version_number) + +if __name__ == '__main__': + unittest.main() + From 3a0f1c063b5a88724dcd0927a34fef1cc1f5d2c0 Mon Sep 17 00:00:00 2001 From: joaopereiramrf Date: Sat, 13 Oct 2018 18:37:10 +0200 Subject: [PATCH 11/13] add support to ftp logs --- library/fastly_service.py | 90 ++++++++++++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 10 deletions(-) diff --git a/library/fastly_service.py b/library/fastly_service.py index ac41bc1..962587d 100644 --- a/library/fastly_service.py +++ b/library/fastly_service.py @@ -70,7 +70,7 @@ required: false description: - List of Syslog loggers - vcls: + upload_vcls: required: false description: - Upload VCL @@ -629,6 +629,41 @@ def __init__(self, config, validate_choices): def sort_key(f): return f.name +class FastlyFTPLogging(FastlyObject): + schema = { + 'name': dict(required=False, type='str'), + 'hostname': dict(required=False, type='str'), + 'port': dict(required=False, type='int'), + 'address': dict(required=False, type='str', default=None, exclude_empty_str=True), + 'format_version': dict(required=False, type='int', default=2), + 'format': dict(required=False, type='str', default='%{%Y-%m-%dT%H:%M:%S}t %h "%r" %>s %b'), + 'ipv4': dict(required=False, type='str', default=None, exclude_empty_str=True, omit_empty=True), + 'message_type': dict(required=False, type='str', default="classic", choices=['classic', 'loggly', 'logplex', 'blank', None]), + 'placement': dict(required=False, type='str', default=None), + 'response_condition': dict(required=False, type='str', default=None, exclude_empty_str=True), + 'user': dict(required=False, type='str', default=None, exclude_empty_str=True), + 'password': dict(required=False, type='str', default=None, exclude_empty_str=True), + 'path': dict(required=False, type='str', default=None, exclude_empty_str=True), + 'timestamp_format': dict(required=False, type='str', default=None, exclude_empty_str=True), + 'period': dict(required=False, type='str', default=None, exclude_empty_str=True), + } + + def __init__(self, config, validate_choices): + self.name = self.read_config(config, validate_choices, 'name') + self.address = self.read_config(config, validate_choices, 'address') + self.format_version = self.read_config(config, validate_choices, 'format_version') + self.format = self.read_config(config, validate_choices, 'format') + self.hostname = self.read_config(config, validate_choices, 'hostname') or self.address + self.ipv4 = self.read_config(config, validate_choices, 'ipv4') + self.message_type = self.read_config(config, validate_choices, 'message_type') + self.placement = self.read_config(config, validate_choices, 'placement') + self.port = self.read_config(config, validate_choices, 'port') + self.response_condition = self.read_config(config, validate_choices, 'response_condition') + self.user = self.read_config(config, validate_choices, 'user') + self.password = self.read_config(config, validate_choices, 'password') + + def sort_key(f): + return f.name class FastlySettings(FastlyObject): schema = { @@ -656,10 +691,11 @@ def __init__(self, cfg, validate_choices=True): self.headers = [FastlyHeader(h, validate_choices) for h in cfg.get('headers') or []] self.response_objects = [FastlyResponseObject(r, validate_choices) for r in cfg.get('response_objects') or []] self.request_settings = [FastlyRequestSetting(r, validate_choices) for r in cfg.get('request_settings') or []] - self.custom_vcls = [] + self.uploads = [FastlyVclUpload(s, validate_choices) for s in cfg.get('uploads') or []] self.snippets = [FastlyVclSnippet(s, validate_choices) for s in cfg.get('snippets') or []] self.s3s = [FastlyS3Logging(s, validate_choices) for s in cfg.get('s3s') or []] self.syslogs = [FastlySyslogLogging(s, validate_choices) for s in cfg.get('syslogs') or []] + self.ftplogs = [FastlyFTPLogging(s, validate_choices) for s in cfg.get('ftplogs') or []] self.settings = FastlySettings(cfg.get('settings'), validate_choices) def __eq__(self, other): @@ -673,10 +709,11 @@ def __eq__(self, other): and sorted(self.headers, key=FastlyHeader.sort_key) == sorted(other.headers, key=FastlyHeader.sort_key) \ and sorted(self.request_settings, key=FastlyRequestSetting.sort_key) == sorted(other.request_settings, key=FastlyRequestSetting.sort_key) \ and sorted(self.response_objects, key=FastlyResponseObject.sort_key) == sorted(other.response_objects, key=FastlyResponseObject.sort_key) \ - and sorted(self.custom_vcls, key=FastlyVclUpload.sort_key) == sorted(other.custom_vcls, key=FastlyVclUpload.sort_key) \ + and sorted(self.uploads, key=FastlyVclUpload.sort_key) == sorted(other.uploads, key=FastlyVclUpload.sort_key) \ and sorted(self.snippets, key=FastlyVclSnippet.sort_key) == sorted(other.snippets, key=FastlyVclSnippet.sort_key) \ and sorted(self.s3s, key=FastlyS3Logging.sort_key) == sorted(other.s3s, key=FastlyS3Logging.sort_key) \ and sorted(self.syslogs, key=FastlySyslogLogging.sort_key) == sorted(other.syslogs, key=FastlySyslogLogging.sort_key) \ + and sorted(self.ftplogs, key=FastlyFTPLogging.sort_key) == sorted(other.ftplogs, key=FastlyFTPLogging.sort_key) \ and self.settings == other.settings def __ne__(self, other): @@ -1028,11 +1065,11 @@ def get_custom_vcl(self, service_id, version): "Error retrieving vcl name for service %s, version %s (%s)" % ( service_id, version, response.payload['detail'])) - def upload_custom_vcl(self, service_id, version, upload_vcl): - response = self._request('/service/%s/version/%s/vcl' % (service_id, version), 'POST', upload_vcl) + def create_custom_vcl(self, service_id, version, upload_vcl): + response = self._request('/service/%s/version/%s/vcl' % (urllib.quote(service_id, ''), version), 'POST', upload_vcl) if response.status == 200: - response = self._request('/service/%s/version/%s/vcl/Main.vcl/main' % (service_id, version), 'PUT', upload_vcl) + response = self._request('/service/%s/version/%s/vcl/Main.vcl/main' % (urllib.quote(service_id, ''), version), 'PUT', upload_vcl) if response.status == 200: return response.payload else: @@ -1117,6 +1154,29 @@ def delete_syslog_logger(self, service_id, version, syslog_logger): raise Exception("Error deleting syslog logger %s service %s, version %s (%s)" % ( syslog_logger, service_id, version, response.error())) + def get_ftp_loggers(self, service_id, version): + response = self._request('/service/%s/version/%s/logging/ftp' % (urllib.quote(service_id, ''), version), 'GET') + if response.status == 200: + return response.payload + raise Exception( + "Error retrieving ftp loggers for service %s, version %s (%s)" % (service_id, version, response.error())) + + def create_ftp_logger(self, service_id, version, syslog): + response = self._request('/service/%s/version/%s/logging/ftp' % (service_id, version), 'POST', syslog) + + if response.status == 200: + return response.payload + else: + raise Exception("Error creating ftp logger '%s' for service %s, version %s (%s)" % (syslog.name, service_id, version, response.error())) + + def delete_ftp_logger(self, service_id, version, syslog_logger): + response = self._request('/service/%s/version/%s/logging/ftp/%s' % (urllib.quote(service_id, ''), version, urllib.quote(syslog_logger, '')), + 'DELETE') + if response.status == 200: + return response.payload + raise Exception("Error deleting ftp logger %s service %s, version %s (%s)" % ( + syslog_logger, service_id, version, response.error())) + def create_settings(self, service_id, version, settings): response = self._request('/service/%s/version/%s/settings' % (urllib.quote(service_id, ''), version), 'PUT', settings) if response.status == 200: @@ -1194,6 +1254,7 @@ def reset_version(self, service_id, version_to_delete): snippets = self.client.get_vcl_snippet_name(service_id, version_to_delete) s3_loggers = self.client.get_s3_loggers(service_id, version_to_delete) syslog_loggers = self.client.get_syslog_loggers(service_id, version_to_delete) + ftp_loggers = self.client.get_ftp_loggers(service_id, version_to_delete) for domain_name in domain: self.client.delete_domain(service_id, version_to_delete, domain_name['name']) @@ -1237,6 +1298,9 @@ def reset_version(self, service_id, version_to_delete): for logger in syslog_loggers: self.client.delete_syslog_logger(service_id, version_to_delete, logger['name']) + for logger in ftp_loggers: + self.client.delete_ftp_logger(service_id, version_to_delete, logger['name']) + def configure_version(self, service_id, configuration, version_number): for domain in configuration.domains: self.client.create_domain(service_id, version_number, domain) @@ -1272,8 +1336,8 @@ def configure_version(self, service_id, configuration, version_number): for response_object in configuration.response_objects: self.client.create_response_object(service_id, version_number, response_object) - for upload_vcl in configuration.custom_vcls: - self.client.upload_custom_vcl(service_id, version_number, upload_vcl) + for upload_vcl in configuration.uploads: + self.client.create_custom_vcl(service_id, version_number, upload_vcl) for vcl_snippet in configuration.snippets: self.client.create_vcl_snippet(service_id, version_number, vcl_snippet) @@ -1284,6 +1348,10 @@ def configure_version(self, service_id, configuration, version_number): for logger in configuration.syslogs: self.client.create_syslog_logger(service_id, version_number, logger) + for logger in configuration.ftplogs: + if logger.name: + self.client.create_ftp_logger(service_id, version_number, logger) + if configuration.settings: self.client.create_settings(service_id, version_number, configuration.settings) @@ -1321,10 +1389,11 @@ def __init__(self): headers=dict(default=None, required=False, type='list'), request_settings=dict(default=None, required=False, type='list'), response_objects=dict(default=None, required=False, type='list'), - vcls=dict(default=None, required=False, type='list'), + upload_vcls=dict(default=None, required=False, type='list'), vcl_snippets=dict(default=None, required=False, type='list'), s3s=dict(default=None, required=False, type='list'), syslogs=dict(default=None, required=False, type='list'), + ftplogs=dict(default=None, required=False, type='list'), settings=dict(default=None, required=False, type='dict'), ), supports_check_mode=False @@ -1352,10 +1421,11 @@ def configuration(self): 'headers': self.module.params['headers'], 'request_settings': self.module.params['request_settings'], 'response_objects': self.module.params['response_objects'], - 'custom_vcls': self.module.params['vcls'], + 'uploads': self.module.params['upload_vcls'], 'snippets': self.module.params['vcl_snippets'], 's3s': self.module.params['s3s'], 'syslogs': self.module.params['syslogs'], + 'ftplogs': self.module.params['ftplogs'], 'settings': self.module.params['settings'] }) except FastlyValidationError as err: From 511451e18206e46b2705f75edb0a7c6daf3d9e3f Mon Sep 17 00:00:00 2001 From: joaopereiramrf Date: Fri, 4 Jan 2019 17:03:12 +0100 Subject: [PATCH 12/13] do not wait for status code, deployment will fail will proper error if there is no main vcl --- library/fastly_service.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/library/fastly_service.py b/library/fastly_service.py index 962587d..b084555 100644 --- a/library/fastly_service.py +++ b/library/fastly_service.py @@ -1067,13 +1067,9 @@ def get_custom_vcl(self, service_id, version): def create_custom_vcl(self, service_id, version, upload_vcl): response = self._request('/service/%s/version/%s/vcl' % (urllib.quote(service_id, ''), version), 'POST', upload_vcl) - if response.status == 200: response = self._request('/service/%s/version/%s/vcl/Main.vcl/main' % (urllib.quote(service_id, ''), version), 'PUT', upload_vcl) - if response.status == 200: - return response.payload - else: - raise Exception("Error uploading VCL '%s' for service %s, version %s (%s)" % (upload_vcl['name'], service_id, version, response.payload['detail'])) + return response.payload else: raise Exception("Error uploading VCL '%s' for service %s, version %s (%s)" % (upload_vcl['name'], service_id, version, response.payload['detail'])) From 875c67594b332f71e350c24b93002842ed66a019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o?= Date: Thu, 15 Aug 2019 14:48:57 +0200 Subject: [PATCH 13/13] Change int to str --- library/fastly_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/fastly_service.py b/library/fastly_service.py index b084555..4dd1677 100644 --- a/library/fastly_service.py +++ b/library/fastly_service.py @@ -607,7 +607,7 @@ class FastlySyslogLogging(FastlyObject): 'tls_ca_cert': dict(required=False, type='str', default=None, exclude_empty_str=True), 'tls_hostname': dict(required=False, type='str', default=None, exclude_empty_str=True), 'token': dict(required=False, type='str', default=None), - 'use_tls': dict(required=False, type='int', default=0), + 'use_tls': dict(required=False, type='str', default='0'), } def __init__(self, config, validate_choices):