diff --git a/examples/cloudfront/cache-policy.gyro b/examples/cloudfront/cache-policy.gyro new file mode 100644 index 000000000..0fea9ad52 --- /dev/null +++ b/examples/cloudfront/cache-policy.gyro @@ -0,0 +1,37 @@ +aws::cloudfront-cache-policy cache-policy-example + cache-policy-config + default-ttl: 3600 + max-ttl: 86400 + min-ttl: 0 + name: "cache-policy-example" + + key-param + accept-encoding-brotli: true + accept-encoding-gzip: true + + headers-config + header-behavior: "whitelist" + headers: [ + "example-header1", + "example-header2" + ] + end + + query-strings-config + query-string-behavior: "whitelist" + query-strings: [ + "example-query1", + "example-query2" + ] + end + + cookies-config + cookie-behavior: "whitelist" + cookies: [ + "example-cookie1", + "example-cookie2" + ] + end + end + end +end diff --git a/examples/cloudfront/cloudfront.gyro b/examples/cloudfront/cloudfront.gyro index 466cb8011..9a3094f17 100644 --- a/examples/cloudfront/cloudfront.gyro +++ b/examples/cloudfront/cloudfront.gyro @@ -1,3 +1,71 @@ +aws::cloudfront-cache-policy cache-policy-example + cache-policy-config + default-ttl: 3600 + max-ttl: 86400 + min-ttl: 0 + name: "cache-policy-example" + + key-param + accept-encoding-brotli: true + accept-encoding-gzip: true + + headers-config + header-behavior: "whitelist" + headers: [ + "example-header1", + "example-header2" + ] + end + + query-strings-config + query-string-behavior: "whitelist" + query-strings: [ + "example-query1", + "example-query2" + ] + end + + cookies-config + cookie-behavior: "whitelist" + cookies: [ + "example-cookie1", + "example-cookie2" + ] + end + end + end +end + +aws::cloudfront-origin-request-policy origin-request-policy-example + origin-request-policy-config + name: "origin-request-policy-example" + + headers-config + header-behavior: "whitelist" + headers: [ + "example-header1", + "example-header2" + ] + end + + query-strings-config + query-string-behavior: "whitelist" + query-strings: [ + "example-query1", + "example-query2" + ] + end + + cookies-config + cookie-behavior: "whitelist" + cookies: [ + "example-cookie1", + "example-cookie2" + ] + end + end +end + aws::cloudfront cloudfront-example enabled: true ipv6-enabled: false @@ -22,7 +90,8 @@ aws::cloudfront cloudfront-example viewer-protocol-policy: "allow-all" allowed-methods: ["GET", "HEAD"] cached-methods: ["GET", "HEAD"] - headers: ["Origin"] + cache-policy: $(aws::cloudfront-cache-policy cache-policy-example) + origin-request-policy: $(aws::cloudfront-origin-request-policy origin-request-policy-example) end behavior diff --git a/examples/cloudfront/origin-request-policy.gyro b/examples/cloudfront/origin-request-policy.gyro new file mode 100644 index 000000000..10dbe7df4 --- /dev/null +++ b/examples/cloudfront/origin-request-policy.gyro @@ -0,0 +1,29 @@ +aws::cloudfront-origin-request-policy origin-request-policy-example + origin-request-policy-config + name: "origin-request-policy-example" + + headers-config + header-behavior: "whitelist" + headers: [ + "example-header1", + "example-header2" + ] + end + + query-strings-config + query-string-behavior: "whitelist" + query-strings: [ + "example-query1", + "example-query2" + ] + end + + cookies-config + cookie-behavior: "whitelist" + cookies: [ + "example-cookie1", + "example-cookie2" + ] + end + end +end diff --git a/src/main/java/gyro/aws/cloudfront/CachePolicyConfig.java b/src/main/java/gyro/aws/cloudfront/CachePolicyConfig.java new file mode 100644 index 000000000..09c4a8f8a --- /dev/null +++ b/src/main/java/gyro/aws/cloudfront/CachePolicyConfig.java @@ -0,0 +1,138 @@ +/* + * Copyright 2024, Brightspot. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.aws.cloudfront; + +import gyro.aws.Copyable; +import gyro.core.resource.Diffable; +import gyro.core.resource.Updatable; +import gyro.core.validation.Required; + +public class CachePolicyConfig + extends Diffable implements Copyable { + + private String comment; + private Long defaultTtl; + private String name; + private Long maxTtl; + private Long minTtl; + private CachePolicyKeyParam keyParam; + + /** + * The comment for the cache policy. + */ + @Updatable + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + /** + * The default time to live for the cache policy. + */ + @Updatable + public Long getDefaultTtl() { + return defaultTtl; + } + + public void setDefaultTtl(Long defaultTtl) { + this.defaultTtl = defaultTtl; + } + + /** + * The name for the cache policy. + */ + @Required + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * The maximum time to live for the cache policy. + */ + @Updatable + public Long getMaxTtl() { + return maxTtl; + } + + public void setMaxTtl(Long maxTtl) { + this.maxTtl = maxTtl; + } + + /** + * The minimum time to live for the cache policy. + */ + @Updatable + public Long getMinTtl() { + return minTtl; + } + + public void setMinTtl(Long minTtl) { + this.minTtl = minTtl; + } + + /** + * The key param for the cache policy. + * + * @subresource gyro.aws.cloudfront.CachePolicyKeyParam + */ + public CachePolicyKeyParam getKeyParam() { + return keyParam; + } + + public void setKeyParam(CachePolicyKeyParam keyParam) { + this.keyParam = keyParam; + } + + @Override + public void copyFrom(software.amazon.awssdk.services.cloudfront.model.CachePolicyConfig model) { + setComment(model.comment()); + setDefaultTtl(model.defaultTTL()); + setName(model.name()); + setMaxTtl(model.maxTTL()); + setMinTtl(model.minTTL()); + + setKeyParam(null); + if (model.parametersInCacheKeyAndForwardedToOrigin() != null) { + CachePolicyKeyParam keyParam = newSubresource(CachePolicyKeyParam.class); + keyParam.copyFrom(model.parametersInCacheKeyAndForwardedToOrigin()); + setKeyParam(keyParam); + } + } + + @Override + public String primaryKey() { + return getName(); + } + + software.amazon.awssdk.services.cloudfront.model.CachePolicyConfig toCachePolicyConfig() { + return software.amazon.awssdk.services.cloudfront.model.CachePolicyConfig.builder() + .comment(getComment()) + .defaultTTL(getDefaultTtl()) + .name(getName()) + .maxTTL(getMaxTtl()) + .minTTL(getMinTtl()) + .parametersInCacheKeyAndForwardedToOrigin(getKeyParam() != null ? getKeyParam().toParametersInCacheKeyAndForwardedToOrigin() : null) + .build(); + } +} diff --git a/src/main/java/gyro/aws/cloudfront/CachePolicyCookiesConfig.java b/src/main/java/gyro/aws/cloudfront/CachePolicyCookiesConfig.java new file mode 100644 index 000000000..41ab47038 --- /dev/null +++ b/src/main/java/gyro/aws/cloudfront/CachePolicyCookiesConfig.java @@ -0,0 +1,118 @@ +/* + * Copyright 2024, Brightspot. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.aws.cloudfront; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import gyro.aws.Copyable; +import gyro.core.resource.Diffable; +import gyro.core.resource.Updatable; +import gyro.core.validation.Required; +import gyro.core.validation.ValidStrings; +import gyro.core.validation.ValidationError; +import software.amazon.awssdk.services.cloudfront.model.CachePolicyCookieBehavior; + +public class CachePolicyCookiesConfig + extends Diffable implements Copyable { + + private CachePolicyCookieBehavior cookieBehavior; + private Set cookies; + + /** + * The cookie behavior for the cache policy. + */ + @Required + @ValidStrings({"none", "whitelist", "allExcept", "all"}) + public CachePolicyCookieBehavior getCookieBehavior() { + return cookieBehavior; + } + + public void setCookieBehavior(CachePolicyCookieBehavior cookieBehavior) { + this.cookieBehavior = cookieBehavior; + } + + /** + * The cookies for the cache policy. + */ + @Updatable + public Set getCookies() { + if (cookies == null) { + cookies = new HashSet<>(); + } + + return cookies; + } + + public void setCookies(Set cookies) { + this.cookies = cookies; + } + + @Override + public String primaryKey() { + return ""; + } + + @Override + public void copyFrom(software.amazon.awssdk.services.cloudfront.model.CachePolicyCookiesConfig model) { + setCookieBehavior(model.cookieBehavior()); + setCookies(null); + if (model.cookies() != null) { + setCookies(new HashSet<>(model.cookies().items())); + } + } + + software.amazon.awssdk.services.cloudfront.model.CachePolicyCookiesConfig toCachePolicyCookiesConfig() { + software.amazon.awssdk.services.cloudfront.model.CachePolicyCookiesConfig.Builder builder = + software.amazon.awssdk.services.cloudfront.model.CachePolicyCookiesConfig.builder() + .cookieBehavior(getCookieBehavior()); + + if (!getCookies().isEmpty()) { + builder.cookies(r -> r.items(getCookies()).quantity(getCookies().size())); + } + + return builder.build(); + } + + @Override + public List validate(Set configuredFields) { + List errors = new ArrayList<>(); + + if (getCookieBehavior() != null) { + if ((getCookieBehavior() != CachePolicyCookieBehavior.NONE + && getCookieBehavior() != CachePolicyCookieBehavior.ALL) + && getCookies().isEmpty()) { + errors.add(new ValidationError( + this, + null, + "'cookies' is required when 'cookie-behavior' is not 'none' or 'all'.")); + } + + if ((getCookieBehavior() == CachePolicyCookieBehavior.NONE || + getCookieBehavior() == CachePolicyCookieBehavior.ALL) && !getCookies().isEmpty()) { + errors.add(new ValidationError( + this, + null, + "'cookies' should be empty when 'cookie-behavior' is 'none' or 'all'.")); + } + } + + return errors; + } +} diff --git a/src/main/java/gyro/aws/cloudfront/CachePolicyFinder.java b/src/main/java/gyro/aws/cloudfront/CachePolicyFinder.java new file mode 100644 index 000000000..4a6057800 --- /dev/null +++ b/src/main/java/gyro/aws/cloudfront/CachePolicyFinder.java @@ -0,0 +1,101 @@ +/* + * Copyright 2024, Brightspot. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.aws.cloudfront; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import gyro.aws.AwsFinder; +import gyro.core.Type; +import software.amazon.awssdk.services.cloudfront.CloudFrontClient; +import software.amazon.awssdk.services.cloudfront.model.CachePolicy; +import software.amazon.awssdk.services.cloudfront.model.CachePolicySummary; +import software.amazon.awssdk.services.cloudfront.model.GetCachePolicyRequest; +import software.amazon.awssdk.services.cloudfront.model.GetCachePolicyResponse; +import software.amazon.awssdk.services.cloudfront.model.ListCachePoliciesRequest; +import software.amazon.awssdk.services.cloudfront.model.ListCachePoliciesResponse; +import software.amazon.awssdk.services.cloudfront.model.NoSuchCachePolicyException; + +/** + * Query cache policy. + * + * Example + * ------- + * + * .. code-block:: gyro + * + * cache-policy: $(external-query aws::cloudfront-cache-policy { id: '' }) + */ +@Type("cloudfront-cache-policy") +public class CachePolicyFinder extends AwsFinder { + + private String id; + + /** + * The ID of the cache policy. + */ + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + protected List findAllAws(CloudFrontClient client) { + List cachePolicies = new ArrayList<>(); + + String marker = null; + ListCachePoliciesResponse response = client.listCachePolicies(ListCachePoliciesRequest.builder().marker(marker).build()); + + if (response.cachePolicyList() != null && response.cachePolicyList().items() != null) { + cachePolicies.addAll(response.cachePolicyList().items().stream() + .map(CachePolicySummary::cachePolicy) + .collect(Collectors.toList())); + } + + return cachePolicies; + } + + @Override + protected List findAws(CloudFrontClient client, Map filters) { + List cachePolicies = new ArrayList<>(); + + if (filters.containsKey("id")) { + try { + GetCachePolicyResponse response = client.getCachePolicy(GetCachePolicyRequest.builder() + .id(filters.get("id")) + .build()); + + if (response.cachePolicy() != null) { + cachePolicies.add(response.cachePolicy()); + } + + } catch (NoSuchCachePolicyException e) { + // Ignore + } + + } else { + cachePolicies.addAll(findAllAws(client)); + } + + return cachePolicies; + } +} diff --git a/src/main/java/gyro/aws/cloudfront/CachePolicyHeadersConfig.java b/src/main/java/gyro/aws/cloudfront/CachePolicyHeadersConfig.java new file mode 100644 index 000000000..fd4851787 --- /dev/null +++ b/src/main/java/gyro/aws/cloudfront/CachePolicyHeadersConfig.java @@ -0,0 +1,115 @@ +/* + * Copyright 2024, Brightspot. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.aws.cloudfront; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import gyro.aws.Copyable; +import gyro.core.resource.Diffable; +import gyro.core.resource.Updatable; +import gyro.core.validation.Required; +import gyro.core.validation.ValidStrings; +import gyro.core.validation.ValidationError; +import software.amazon.awssdk.services.cloudfront.model.CachePolicyHeaderBehavior; + +public class CachePolicyHeadersConfig + extends Diffable implements Copyable { + + private CachePolicyHeaderBehavior headerBehavior; + private Set headers; + + /** + * The header behavior for the cache policy. + */ + @Required + @ValidStrings({"none", "whitelist"}) + public CachePolicyHeaderBehavior getHeaderBehavior() { + return headerBehavior; + } + + public void setHeaderBehavior(CachePolicyHeaderBehavior headerBehavior) { + this.headerBehavior = headerBehavior; + } + + /** + * The headers for the cache policy. + */ + @Updatable + public Set getHeaders() { + if (headers == null) { + headers = new HashSet<>(); + } + + return headers; + } + + public void setHeaders(Set headers) { + this.headers = headers; + } + + @Override + public void copyFrom(software.amazon.awssdk.services.cloudfront.model.CachePolicyHeadersConfig model) { + setHeaderBehavior(model.headerBehavior()); + setHeaders(null); + if (model.headers() != null) { + setHeaders(new HashSet<>(model.headers().items())); + } + } + + @Override + public String primaryKey() { + return ""; + } + + software.amazon.awssdk.services.cloudfront.model.CachePolicyHeadersConfig toCachePolicyHeadersConfig() { + software.amazon.awssdk.services.cloudfront.model.CachePolicyHeadersConfig.Builder builder = + software.amazon.awssdk.services.cloudfront.model.CachePolicyHeadersConfig.builder() + .headerBehavior(getHeaderBehavior()); + + if (!getHeaders().isEmpty()) { + builder.headers(r -> r.items(getHeaders()).quantity(getHeaders().size())); + } + + return builder.build(); + } + + @Override + public List validate(Set configuredFields) { + List errors = new ArrayList<>(); + + if (getHeaderBehavior() != null) { + if (getHeaderBehavior() != CachePolicyHeaderBehavior.NONE && getHeaders().isEmpty()) { + errors.add(new ValidationError( + this, + null, + "'headers' is required when 'header-behavior' is not 'none'.")); + } + + if (getHeaderBehavior() == CachePolicyHeaderBehavior.NONE && !getHeaders().isEmpty()) { + errors.add(new ValidationError( + this, + null, + "'headers' should be empty when 'headers-behavior' is 'none'.")); + } + } + + return errors; + } +} diff --git a/src/main/java/gyro/aws/cloudfront/CachePolicyKeyParam.java b/src/main/java/gyro/aws/cloudfront/CachePolicyKeyParam.java new file mode 100644 index 000000000..88a46f9dd --- /dev/null +++ b/src/main/java/gyro/aws/cloudfront/CachePolicyKeyParam.java @@ -0,0 +1,140 @@ +/* + * Copyright 2024, Brightspot. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.aws.cloudfront; + +import gyro.aws.Copyable; +import gyro.core.resource.Diffable; +import gyro.core.resource.Updatable; +import gyro.core.validation.Required; +import software.amazon.awssdk.services.cloudfront.model.ParametersInCacheKeyAndForwardedToOrigin; + +public class CachePolicyKeyParam extends Diffable implements Copyable { + + private CachePolicyCookiesConfig cookiesConfig; + private CachePolicyHeadersConfig headersConfig; + private CachePolicyQueryStringsConfig queryStringsConfig; + private Boolean acceptEncodingBrotli; + private Boolean acceptEncodingGzip; + + /** + * The cookies configuration for the cache policy. + * + * @subresource gyro.aws.cloudfront.CachePolicyCookiesConfig + */ + public CachePolicyCookiesConfig getCookiesConfig() { + return cookiesConfig; + } + + public void setCookiesConfig(CachePolicyCookiesConfig cookiesConfig) { + this.cookiesConfig = cookiesConfig; + } + + /** + * The headers configuration for the cache policy. + * + * @subresource gyro.aws.cloudfront.CachePolicyHeadersConfig + */ + public CachePolicyHeadersConfig getHeadersConfig() { + return headersConfig; + } + + public void setHeadersConfig(CachePolicyHeadersConfig headersConfig) { + this.headersConfig = headersConfig; + } + + /** + * The query strings configuration for the cache policy. + * + * @subresource gyro.aws.cloudfront.CachePolicyQueryStringsConfig + */ + public CachePolicyQueryStringsConfig getQueryStringsConfig() { + return queryStringsConfig; + } + + public void setQueryStringsConfig(CachePolicyQueryStringsConfig queryStringsConfig) { + this.queryStringsConfig = queryStringsConfig; + } + + /** + * Enable accept encoding brotli. + */ + @Required + @Updatable + public Boolean getAcceptEncodingBrotli() { + return acceptEncodingBrotli; + } + + public void setAcceptEncodingBrotli(Boolean acceptEncodingBrotli) { + this.acceptEncodingBrotli = acceptEncodingBrotli; + } + + /** + * Enable accept encoding gzip. + */ + @Required + @Updatable + public Boolean getAcceptEncodingGzip() { + return acceptEncodingGzip; + } + + public void setAcceptEncodingGzip(Boolean acceptEncodingGzip) { + this.acceptEncodingGzip = acceptEncodingGzip; + } + + @Override + public void copyFrom(ParametersInCacheKeyAndForwardedToOrigin model) { + setCookiesConfig(null); + if (model.cookiesConfig() != null) { + CachePolicyCookiesConfig cookiesConfig = newSubresource(CachePolicyCookiesConfig.class); + cookiesConfig.copyFrom(model.cookiesConfig()); + setCookiesConfig(cookiesConfig); + } + + setHeadersConfig(null); + if (model.headersConfig() != null) { + CachePolicyHeadersConfig headersConfig = newSubresource(CachePolicyHeadersConfig.class); + headersConfig.copyFrom(model.headersConfig()); + setHeadersConfig(headersConfig); + } + + setQueryStringsConfig(null); + if (model.queryStringsConfig() != null) { + CachePolicyQueryStringsConfig queryStringsConfig = newSubresource(CachePolicyQueryStringsConfig.class); + queryStringsConfig.copyFrom(model.queryStringsConfig()); + setQueryStringsConfig(queryStringsConfig); + } + + setAcceptEncodingGzip(model.enableAcceptEncodingGzip()); + setAcceptEncodingBrotli(model.enableAcceptEncodingBrotli()); + } + + @Override + public String primaryKey() { + return ""; + } + + ParametersInCacheKeyAndForwardedToOrigin toParametersInCacheKeyAndForwardedToOrigin() { + return ParametersInCacheKeyAndForwardedToOrigin.builder() + .cookiesConfig(getCookiesConfig() != null ? getCookiesConfig().toCachePolicyCookiesConfig() : null) + .headersConfig(getHeadersConfig() != null ? getHeadersConfig().toCachePolicyHeadersConfig() : null) + .queryStringsConfig( + getQueryStringsConfig() != null ? getQueryStringsConfig().toCachePolicyQueryStringsConfig() : null) + .enableAcceptEncodingBrotli(getAcceptEncodingBrotli()) + .enableAcceptEncodingGzip(getAcceptEncodingGzip()) + .build(); + } +} diff --git a/src/main/java/gyro/aws/cloudfront/CachePolicyQueryStringsConfig.java b/src/main/java/gyro/aws/cloudfront/CachePolicyQueryStringsConfig.java new file mode 100644 index 000000000..59ffb2de5 --- /dev/null +++ b/src/main/java/gyro/aws/cloudfront/CachePolicyQueryStringsConfig.java @@ -0,0 +1,118 @@ +/* + * Copyright 2024, Brightspot. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.aws.cloudfront; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import gyro.aws.Copyable; +import gyro.core.resource.Diffable; +import gyro.core.resource.Updatable; +import gyro.core.validation.Required; +import gyro.core.validation.ValidStrings; +import gyro.core.validation.ValidationError; +import software.amazon.awssdk.services.cloudfront.model.CachePolicyQueryStringBehavior; + +public class CachePolicyQueryStringsConfig extends Diffable + implements Copyable { + + private CachePolicyQueryStringBehavior queryStringBehavior; + private Set queryStrings; + + /** + * The query string behavior for this cache policy. + */ + @Required + @ValidStrings({"none", "whitelist", "allExcept", "all"}) + public CachePolicyQueryStringBehavior getQueryStringBehavior() { + return queryStringBehavior; + } + + public void setQueryStringBehavior(CachePolicyQueryStringBehavior queryStringBehavior) { + this.queryStringBehavior = queryStringBehavior; + } + + /** + * The query strings for this cache policy. + */ + @Updatable + public Set getQueryStrings() { + if (queryStrings == null) { + queryStrings = new HashSet<>(); + } + + return queryStrings; + } + + public void setQueryStrings(Set queryStrings) { + this.queryStrings = queryStrings; + } + + @Override + public String primaryKey() { + return ""; + } + + @Override + public void copyFrom(software.amazon.awssdk.services.cloudfront.model.CachePolicyQueryStringsConfig model) { + setQueryStringBehavior(model.queryStringBehavior()); + setQueryStrings(null); + if (model.queryStrings() != null) { + setQueryStrings(new HashSet<>(model.queryStrings().items())); + } + } + + software.amazon.awssdk.services.cloudfront.model.CachePolicyQueryStringsConfig toCachePolicyQueryStringsConfig() { + software.amazon.awssdk.services.cloudfront.model.CachePolicyQueryStringsConfig.Builder builder = + software.amazon.awssdk.services.cloudfront.model.CachePolicyQueryStringsConfig.builder() + .queryStringBehavior(getQueryStringBehavior()); + + if (!getQueryStrings().isEmpty()) { + builder.queryStrings(r -> r.items(getQueryStrings()).quantity(getQueryStrings().size())); + } + + return builder.build(); + } + + @Override + public List validate(Set configuredFields) { + List errors = new ArrayList<>(); + + if (getQueryStringBehavior() != null) { + if ((getQueryStringBehavior() != CachePolicyQueryStringBehavior.NONE + && getQueryStringBehavior() != CachePolicyQueryStringBehavior.ALL) + && getQueryStrings().isEmpty()) { + errors.add(new ValidationError( + this, + null, + "'query-strings' is required when 'query-string-behavior' is not 'none' or 'all'.")); + } + + if ((getQueryStringBehavior() == CachePolicyQueryStringBehavior.NONE || + getQueryStringBehavior() == CachePolicyQueryStringBehavior.ALL) && !getQueryStrings().isEmpty()) { + errors.add(new ValidationError( + this, + null, + "'query-strings' should be empty when 'query-string-behavior' is 'none' or 'all'.")); + } + } + + return errors; + } +} diff --git a/src/main/java/gyro/aws/cloudfront/CachePolicyResource.java b/src/main/java/gyro/aws/cloudfront/CachePolicyResource.java new file mode 100644 index 000000000..0d42543c3 --- /dev/null +++ b/src/main/java/gyro/aws/cloudfront/CachePolicyResource.java @@ -0,0 +1,192 @@ +/* + * Copyright 2024, Brightspot. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.aws.cloudfront; + +import java.util.Set; + +import gyro.aws.AwsResource; +import gyro.aws.Copyable; +import gyro.core.GyroUI; +import gyro.core.Type; +import gyro.core.resource.Id; +import gyro.core.resource.Output; +import gyro.core.resource.Resource; +import gyro.core.resource.Updatable; +import gyro.core.scope.State; +import gyro.core.validation.Required; +import software.amazon.awssdk.services.cloudfront.CloudFrontClient; +import software.amazon.awssdk.services.cloudfront.model.CachePolicy; +import software.amazon.awssdk.services.cloudfront.model.GetCachePolicyResponse; +import software.amazon.awssdk.services.cloudfront.model.NoSuchCachePolicyException; + +/** + * Create a cloudfront cache policy. + * + * Example + * ------- + * + * .. code-block:: gyro + * + * aws::cloudfront-cache-policy cache-policy-example + * cache-policy-config + * default-ttl: 3600 + * max-ttl: 86400 + * min-ttl: 0 + * name: "cache-policy-example" + * + * key-param + * accept-encoding-brotli: true + * accept-encoding-gzip: true + * + * headers-config + * header-behavior: "whitelist" + * headers: [ + * "example-header1", + * "example-header2" + * ] + * end + * + * query-strings-config + * query-string-behavior: "whitelist" + * query-strings: [ + * "example-query1", + * "example-query2" + * ] + * end + * + * cookies-config + * cookie-behavior: "whitelist" + * cookies: [ + * "example-cookie1", + * "example-cookie2" + * ] + * end + * end + * end + * end + */ +@Type("cloudfront-cache-policy") +public class CachePolicyResource extends AwsResource implements Copyable { + + private CachePolicyConfig cachePolicyConfig; + private String id; + + /** + * The cache policy configuration. + * + * @subresource gyro.aws.cloudfront.CachePolicyConfig + */ + @Required + @Updatable + public CachePolicyConfig getCachePolicyConfig() { + return cachePolicyConfig; + } + + public void setCachePolicyConfig(CachePolicyConfig cachePolicyConfig) { + this.cachePolicyConfig = cachePolicyConfig; + } + + /** + * The ID for the cache policy. + */ + @Output + @Id + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public void copyFrom(CachePolicy model) { + setId(model.id()); + + setCachePolicyConfig(null); + if (model.cachePolicyConfig() != null) { + CachePolicyConfig config = newSubresource(CachePolicyConfig.class); + config.copyFrom(model.cachePolicyConfig()); + setCachePolicyConfig(config); + } + } + + @Override + public boolean refresh() { + + CloudFrontClient client = getCloudFrontClient(); + + try { + GetCachePolicyResponse cachePolicy = client.getCachePolicy(r -> r.id(getId())); + + copyFrom(cachePolicy.cachePolicy()); + + return true; + } catch (NoSuchCachePolicyException ex) { + return false; + } + } + + @Override + public void create(GyroUI ui, State state) throws Exception { + CloudFrontClient client = getCloudFrontClient(); + + CachePolicy cachePolicy = client.createCachePolicy(r -> r.cachePolicyConfig(getCachePolicyConfig().toCachePolicyConfig())).cachePolicy(); + + setId(cachePolicy.id()); + } + + @Override + public void update(GyroUI ui, State state, Resource current, Set changedFieldNames) throws Exception { + CloudFrontClient client = getCloudFrontClient(); + + client.updateCachePolicy(r -> r + .cachePolicyConfig(getCachePolicyConfig().toCachePolicyConfig()) + .id(getId()) + .ifMatch(getCachePolicyEtag(client)) + ); + } + + @Override + public void delete(GyroUI ui, State state) throws Exception { + CloudFrontClient client = getCloudFrontClient(); + + client.deleteCachePolicy(r -> r.id(getId()).ifMatch(getCachePolicyEtag(client))); + } + + private CloudFrontClient getCloudFrontClient() { + CloudFrontClient client = createClient( + CloudFrontClient.class, + "us-east-1", + "https://cloudfront.amazonaws.com"); + + return client; + } + + private String getCachePolicyEtag(CloudFrontClient client) { + String etag = null; + + try { + GetCachePolicyResponse response = client.getCachePolicy(r -> r.id(getId())); + etag = response.eTag(); + } catch (NoSuchCachePolicyException ex) { + // ignore + } + + return etag; + } +} diff --git a/src/main/java/gyro/aws/cloudfront/CloudFrontCacheBehavior.java b/src/main/java/gyro/aws/cloudfront/CloudFrontCacheBehavior.java index 4e5b98f0d..c234a998c 100644 --- a/src/main/java/gyro/aws/cloudfront/CloudFrontCacheBehavior.java +++ b/src/main/java/gyro/aws/cloudfront/CloudFrontCacheBehavior.java @@ -16,9 +16,14 @@ package gyro.aws.cloudfront; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + import gyro.aws.Copyable; import gyro.core.resource.Diffable; import gyro.core.resource.Updatable; +import gyro.core.validation.ConflictsWith; import gyro.core.validation.ValidStrings; import software.amazon.awssdk.services.cloudfront.model.CacheBehavior; import software.amazon.awssdk.services.cloudfront.model.DefaultCacheBehavior; @@ -30,10 +35,6 @@ import software.amazon.awssdk.services.cloudfront.model.LambdaFunctionAssociations; import software.amazon.awssdk.services.cloudfront.model.TrustedSigners; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; - public class CloudFrontCacheBehavior extends Diffable implements Copyable { private String targetOriginId; @@ -55,6 +56,8 @@ public class CloudFrontCacheBehavior extends Diffable implements Copyable lambdaFunctions; private Set functionAssociations; + private CachePolicyResource cachePolicy; + private OriginRequestPolicyResource originRequestPolicy; /** * The ID for the origin to route requests to when the path pattern matches this cache behavior. @@ -98,8 +101,13 @@ public void setViewerProtocolPolicy(String viewerProtocolPolicy) { /** * The minimum time objects will be cached in this distribution. + * Deprecated in favor of {@link CachePolicyResource}. For more information, See + * `Creating cache policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-the-cache-key.html#cache-key-create-cache-policy">` or + * `Using the managed cache policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-cache-policies.html">` */ @Updatable + @Deprecated + @ConflictsWith("cache-policy") public Long getMinTtl() { if (minTtl == null) { minTtl = 0L; @@ -146,8 +154,18 @@ public void setCachedMethods(Set cachedMethods) { /** * Headers to include the cache key for an object. + * Deprecated in favor of {@link CachePolicyResource} or {@link OriginRequestPolicyResource} + * If you want to include values in the cache key, use a cache policy. For more information, See + * `Creating cache policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-the-cache-key.html#cache-key-create-cache-policy">` or + * `Using the managed cache policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-cache-policies.html">` + * If you want to send values to the origin but not include them in the cache key, use an origin request policy. + * For more information, See + * `Creating origin request policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-origin-requests.html#origin-request-create-origin-request-policy">` or + * `Using the managed origin request policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-origin-request-policies.html">` */ @Updatable + @Deprecated + @ConflictsWith("cache-policy") public Set getHeaders() { if (headers == null) { headers = new HashSet<>(); @@ -162,8 +180,18 @@ public void setHeaders(Set headers) { /** * Whether to forward to cookies to the origin. + * Deprecated in favor of {@link CachePolicyResource} or {@link OriginRequestPolicyResource} + * If you want to include values in the cache key, use a cache policy. For more information, See + * `Creating cache policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-the-cache-key.html#cache-key-create-cache-policy">` or + * `Using the managed cache policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-cache-policies.html">` + * If you want to send values to the origin but not include them in the cache key, use an origin request policy. + * For more information, See + * `Creating origin request policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-origin-requests.html#origin-request-create-origin-request-policy">` or + * `Using the managed origin request policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-origin-request-policies.html">` */ @Updatable + @Deprecated + @ConflictsWith("cache-policy") public String getForwardCookies() { if (forwardCookies != null) { return forwardCookies.toLowerCase(); @@ -178,8 +206,18 @@ public void setForwardCookies(String forwardCookies) { /** * Whitelist of cookies to include the cache key for an object. + * Deprecated in favor of {@link CachePolicyResource} or {@link OriginRequestPolicyResource} + * If you want to include values in the cache key, use a cache policy. For more information, See + * `Creating cache policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-the-cache-key.html#cache-key-create-cache-policy">` or + * `Using the managed cache policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-cache-policies.html">` + * If you want to send values to the origin but not include them in the cache key, use an origin request policy. + * For more information, See + * `Creating origin request policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-origin-requests.html#origin-request-create-origin-request-policy">` or + * `Using the managed origin request policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-origin-request-policies.html">` */ @Updatable + @Deprecated + @ConflictsWith("cache-policy") public Set getCookies() { if (cookies == null) { cookies = new HashSet<>(); @@ -210,8 +248,13 @@ public void setSmoothStreaming(Boolean smoothStreaming) { /** * The time objects will be cached in this distribution. Only applies when one of ``Cache-Control: max-age``, ``Cache-Control: s-maxage``, or ``Expires`` are not returned by the origin. + * Deprecated in favor of {@link CachePolicyResource}. For more information, See + * `Creating cache policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-the-cache-key.html#cache-key-create-cache-policy">` or + * `Using the managed cache policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-cache-policies.html">` */ @Updatable + @Deprecated + @ConflictsWith("cache-policy") public Long getDefaultTtl() { if (defaultTtl == null) { defaultTtl = 86400L; @@ -226,8 +269,13 @@ public void setDefaultTtl(Long defaultTtl) { /** * The maximum time objects will be cached in this distribution. + * Deprecated in favor of {@link CachePolicyResource}. For more information, See + * `Creating cache policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-the-cache-key.html#cache-key-create-cache-policy">` or + * `Using the managed cache policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-cache-policies.html">` */ @Updatable + @Deprecated + @ConflictsWith("cache-policy") public Long getMaxTtl() { if (maxTtl == null) { maxTtl = 31536000L; @@ -258,8 +306,18 @@ public void setCompress(Boolean compress) { /** * Whether to forward query strings to origin. If true, query string parameters become part of the cache key. + * Deprecated in favor of {@link CachePolicyResource} or {@link OriginRequestPolicyResource} + * If you want to include values in the cache key, use a cache policy. For more information, See + * `Creating cache policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-the-cache-key.html#cache-key-create-cache-policy">` or + * `Using the managed cache policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-cache-policies.html">` + * If you want to send values to the origin but not include them in the cache key, use an origin request policy. + * For more information, See + * `Creating origin request policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-origin-requests.html#origin-request-create-origin-request-policy">` or + * `Using the managed origin request policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-origin-request-policies.html">` */ @Updatable + @Deprecated + @ConflictsWith("cache-policy") public Boolean getQueryString() { if (queryString == null) { queryString = false; @@ -274,8 +332,18 @@ public void setQueryString(Boolean queryString) { /** * Query string parameters that should be used in the cache key. + * Deprecated in favor of {@link CachePolicyResource} or {@link OriginRequestPolicyResource} + * If you want to include values in the cache key, use a cache policy. For more information, See + * `Creating cache policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-the-cache-key.html#cache-key-create-cache-policy">` or + * `Using the managed cache policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-cache-policies.html">` + * If you want to send values to the origin but not include them in the cache key, use an origin request policy. + * For more information, See + * `Creating origin request policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-origin-requests.html#origin-request-create-origin-request-policy">` or + * `Using the managed origin request policies <"https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-origin-request-policies.html">` */ @Updatable + @Deprecated + @ConflictsWith("cache-policy") public Set getQueryStringCacheKeys() { if (queryStringCacheKeys == null) { queryStringCacheKeys = new HashSet<>(); @@ -355,6 +423,30 @@ public void setFunctionAssociations(Set h.items(getHeaders()).quantity(getHeaders().size())) - .cookies(c -> c.forward(getForwardCookies()).whitelistedNames(w -> w.items(getCookies()).quantity(getCookies().size()))) - .queryString(getQueryString()) - .queryStringCacheKeys(q -> q.items(getQueryStringCacheKeys()).quantity(getQueryStringCacheKeys().size())) - .build(); - TrustedSigners trustedSigners = TrustedSigners.builder() .items(getTrustedSigners()) .quantity(getTrustedSigners().size()) @@ -455,33 +549,41 @@ DefaultCacheBehavior toDefaultCacheBehavior() { .quantity(getFunctionAssociations().size()) .build(); - return DefaultCacheBehavior.builder() + DefaultCacheBehavior.Builder builder = DefaultCacheBehavior.builder() .allowedMethods(am -> am.itemsWithStrings(getAllowedMethods()) .quantity(getAllowedMethods().size()) .cachedMethods(cm -> cm.itemsWithStrings(getCachedMethods()).quantity(getCachedMethods().size())) ) - .defaultTTL(getDefaultTtl()) - .maxTTL(getMaxTtl()) - .minTTL(getMinTtl()) .smoothStreaming(getSmoothStreaming()) .targetOriginId(getTargetOriginId()) - .forwardedValues(forwardedValues) .trustedSigners(trustedSigners) .lambdaFunctionAssociations(lambdaFunctionAssociations) .functionAssociations(functionAssociations) .viewerProtocolPolicy(getViewerProtocolPolicy()) .fieldLevelEncryptionId(getFieldLevelEncryptionId()) .compress(getCompress()) - .build(); + .cachePolicyId(getCachePolicy() != null ? getCachePolicy().getId() : null) + .originRequestPolicyId(getOriginRequestPolicy() != null ? getOriginRequestPolicy().getId() : null); + + if (getCachePolicy() == null) { + ForwardedValues forwardedValues = ForwardedValues.builder() + .headers(h -> h.items(getHeaders()).quantity(getHeaders().size())) + .cookies(c -> c.forward(getForwardCookies()) + .whitelistedNames(w -> w.items(getCookies()).quantity(getCookies().size()))) + .queryString(getQueryString()) + .queryStringCacheKeys( + q -> q.items(getQueryStringCacheKeys()).quantity(getQueryStringCacheKeys().size())) + .build(); + builder.forwardedValues(forwardedValues) + .defaultTTL(getDefaultTtl()) + .maxTTL(getMaxTtl()) + .minTTL(getMinTtl()); + } + + return builder.build(); } CacheBehavior toCachBehavior() { - ForwardedValues forwardedValues = ForwardedValues.builder() - .headers(h -> h.items(getHeaders()).quantity(getHeaders().size())) - .cookies(c -> c.forward(getForwardCookies()).whitelistedNames(w -> w.items(getCookies()).quantity(getCookies().size()))) - .queryString(getQueryString()) - .queryStringCacheKeys(q -> q.items(getQueryStringCacheKeys()).quantity(getQueryStringCacheKeys().size())) - .build(); TrustedSigners trustedSigners = TrustedSigners.builder() .items(getTrustedSigners()) @@ -499,24 +601,38 @@ CacheBehavior toCachBehavior() { .quantity(getFunctionAssociations().size()) .build(); - return CacheBehavior.builder() + CacheBehavior.Builder builder = CacheBehavior.builder() .allowedMethods(am -> am.itemsWithStrings(getAllowedMethods()) .quantity(getAllowedMethods().size()) .cachedMethods(cm -> cm.itemsWithStrings(getCachedMethods()).quantity(getCachedMethods().size())) ) - .defaultTTL(getDefaultTtl()) - .maxTTL(getMaxTtl()) - .minTTL(getMinTtl()) .smoothStreaming(getSmoothStreaming()) .targetOriginId(getTargetOriginId()) .pathPattern(getPathPattern()) - .forwardedValues(forwardedValues) .trustedSigners(trustedSigners) .lambdaFunctionAssociations(lambdaFunctionAssociations) .functionAssociations(functionAssociations) .viewerProtocolPolicy(getViewerProtocolPolicy()) .fieldLevelEncryptionId(getFieldLevelEncryptionId()) .compress(getCompress()) - .build(); + .cachePolicyId(getCachePolicy() != null ? getCachePolicy().getId() : null) + .originRequestPolicyId(getOriginRequestPolicy() != null ? getOriginRequestPolicy().getId() : null); + + if (getCachePolicy() == null) { + ForwardedValues forwardedValues = ForwardedValues.builder() + .headers(h -> h.items(getHeaders()).quantity(getHeaders().size())) + .cookies(c -> c.forward(getForwardCookies()) + .whitelistedNames(w -> w.items(getCookies()).quantity(getCookies().size()))) + .queryString(getQueryString()) + .queryStringCacheKeys( + q -> q.items(getQueryStringCacheKeys()).quantity(getQueryStringCacheKeys().size())) + .build(); + builder.forwardedValues(forwardedValues) + .defaultTTL(getDefaultTtl()) + .maxTTL(getMaxTtl()) + .minTTL(getMinTtl()); + } + + return builder.build(); } } diff --git a/src/main/java/gyro/aws/cloudfront/CloudFrontResource.java b/src/main/java/gyro/aws/cloudfront/CloudFrontResource.java index 9ae793dbc..ca947822e 100644 --- a/src/main/java/gyro/aws/cloudfront/CloudFrontResource.java +++ b/src/main/java/gyro/aws/cloudfront/CloudFrontResource.java @@ -73,10 +73,15 @@ * aws::cloudfront cloudfront-example * enabled: true * ipv6-enabled: false - * comment: "cloudfront-example - static asset cache" + * comment: "$(project) - static asset cache" * * origin - * id: $(aws::s3-bucket bucket).name + * id: "S3-$(project)-brightspot" + * domain-name: "$(project)-brightspot.s3.us-east-1.amazonaws.com" + * end + * + * origin + * id: "elb-$(project)-web" * domain-name: "www.google.com" * * custom-origin @@ -85,16 +90,17 @@ * end * * default-cache-behavior - * target-origin-id: $(aws::s3-bucket bucket).name + * target-origin-id: "S3-$(project)-brightspot" * viewer-protocol-policy: "allow-all" * allowed-methods: ["GET", "HEAD"] * cached-methods: ["GET", "HEAD"] - * headers: ["Origin"] + * cache-policy: $(aws::cloudfront-cache-policy cache-policy-example) + * origin-request-policy: $(aws::cloudfront-origin-request-policy origin-request-policy-example) * end * * behavior * path-pattern: "/dims?/*" - * target-origin-id: $(aws::s3-bucket bucket).name + * target-origin-id: "elb-$(project)-web" * viewer-protocol-policy: "allow-all" * allowed-methods: ["GET", "HEAD"] * query-string: true @@ -105,21 +111,17 @@ * restrictions: ["US"] * end * - * custom-error-response - * error-code: 400 - * ttl: 0 - * end - * - * logging - * bucket: $(aws::s3-bucket bucket) - * bucket-prefix: "my-bucket/logs" - * include-cookies: false - * end + * @for error-code, ttl -in [400, 0, 403, 5, 404, 5, 500, 0, 502, 0, 503, 0, 504, 0] + * custom-error-response + * error-code: $(error-code) + * ttl: $(ttl) + * end + * @end * * tags: { * Name: "content cache" * } - * end + * end */ @Type("cloudfront") public class CloudFrontResource extends AwsResource implements Copyable { diff --git a/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyConfig.java b/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyConfig.java new file mode 100644 index 000000000..7d0c9a7f4 --- /dev/null +++ b/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyConfig.java @@ -0,0 +1,138 @@ +/* + * Copyright 2024, Brightspot. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.aws.cloudfront; + +import gyro.aws.Copyable; +import gyro.core.resource.Diffable; +import gyro.core.resource.Updatable; +import gyro.core.validation.Required; + +public class OriginRequestPolicyConfig + extends Diffable implements Copyable { + + private String comment; + private String name; + private OriginRequestPolicyCookiesConfig cookiesConfig; + private OriginRequestPolicyHeadersConfig headersConfig; + private OriginRequestPolicyQueryStringsConfig queryStringsConfig; + + /** + * The cookies configuration for the origin request policy. + * + * @subresource gyro.aws.cloudfront.OriginRequestPolicyCookiesConfig + */ + public OriginRequestPolicyCookiesConfig getCookiesConfig() { + return cookiesConfig; + } + + public void setCookiesConfig(OriginRequestPolicyCookiesConfig cookiesConfig) { + this.cookiesConfig = cookiesConfig; + } + + /** + * The headers configuration for the origin request policy. + * + * @subresource gyro.aws.cloudfront.OriginRequestPolicyHeadersConfig + */ + public OriginRequestPolicyHeadersConfig getHeadersConfig() { + return headersConfig; + } + + public void setHeadersConfig(OriginRequestPolicyHeadersConfig headersConfig) { + this.headersConfig = headersConfig; + } + + /** + * The query strings configuration for the origin request policy. + * + * @subresource gyro.aws.cloudfront.OriginRequestPolicyQueryStringsConfig + */ + public OriginRequestPolicyQueryStringsConfig getQueryStringsConfig() { + return queryStringsConfig; + } + + public void setQueryStringsConfig(OriginRequestPolicyQueryStringsConfig queryStringsConfig) { + this.queryStringsConfig = queryStringsConfig; + } + + /** + * The comment for the origin request policy. + */ + @Updatable + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + /** + * The name for the origin request policy. + */ + @Required + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public void copyFrom(software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyConfig model) { + setComment(model.comment()); + setName(model.name()); + + setCookiesConfig(null); + if (model.cookiesConfig() != null) { + OriginRequestPolicyCookiesConfig cookiesConfig = newSubresource(OriginRequestPolicyCookiesConfig.class); + cookiesConfig.copyFrom(model.cookiesConfig()); + setCookiesConfig(cookiesConfig); + } + + setHeadersConfig(null); + if (model.headersConfig() != null) { + OriginRequestPolicyHeadersConfig headersConfig = newSubresource(OriginRequestPolicyHeadersConfig.class); + headersConfig.copyFrom(model.headersConfig()); + setHeadersConfig(headersConfig); + } + + setQueryStringsConfig(null); + if (model.queryStringsConfig() != null) { + OriginRequestPolicyQueryStringsConfig queryStringsConfig = newSubresource(OriginRequestPolicyQueryStringsConfig.class); + queryStringsConfig.copyFrom(model.queryStringsConfig()); + setQueryStringsConfig(queryStringsConfig); + } + } + + @Override + public String primaryKey() { + return getName(); + } + + software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyConfig toOriginRequestPolicyConfig() { + return software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyConfig.builder() + .comment(getComment()) + .name(getName()) + .cookiesConfig(getCookiesConfig() != null ? getCookiesConfig().toOriginRequestPolicyCookiesConfig() : null) + .headersConfig(getHeadersConfig() != null ? getHeadersConfig().toOriginRequestPolicyHeadersConfig() : null) + .queryStringsConfig( + getQueryStringsConfig() != null ? getQueryStringsConfig().toOriginRequestPolicyQueryStringsConfig() : null) + .build(); + } +} diff --git a/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyCookiesConfig.java b/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyCookiesConfig.java new file mode 100644 index 000000000..c1c59d60b --- /dev/null +++ b/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyCookiesConfig.java @@ -0,0 +1,119 @@ +/* + * Copyright 2024, Brightspot. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.aws.cloudfront; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import gyro.aws.Copyable; +import gyro.core.resource.Diffable; +import gyro.core.resource.Updatable; +import gyro.core.validation.Required; +import gyro.core.validation.ValidStrings; +import gyro.core.validation.ValidationError; +import software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyCookieBehavior; + +public class OriginRequestPolicyCookiesConfig + extends Diffable + implements Copyable { + + private OriginRequestPolicyCookieBehavior cookieBehavior; + private Set cookies; + + /** + * The cookie behavior for the origin request policy. + */ + @Required + @ValidStrings({"none", "whitelist", "allExcept", "all"}) + public OriginRequestPolicyCookieBehavior getCookieBehavior() { + return cookieBehavior; + } + + public void setCookieBehavior(OriginRequestPolicyCookieBehavior cookieBehavior) { + this.cookieBehavior = cookieBehavior; + } + + /** + * The cookies for the origin request policy. + */ + @Updatable + public Set getCookies() { + if (cookies == null) { + cookies = new HashSet<>(); + } + + return cookies; + } + + public void setCookies(Set cookies) { + this.cookies = cookies; + } + + @Override + public String primaryKey() { + return ""; + } + + @Override + public void copyFrom(software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyCookiesConfig model) { + setCookieBehavior(model.cookieBehavior()); + setCookies(null); + if (model.cookies() != null) { + setCookies(new HashSet<>(model.cookies().items())); + } + } + + software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyCookiesConfig toOriginRequestPolicyCookiesConfig() { + software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyCookiesConfig.Builder builder = + software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyCookiesConfig.builder() + .cookieBehavior(getCookieBehavior()); + + if (!getCookies().isEmpty()) { + builder.cookies(r -> r.items(getCookies()).quantity(getCookies().size())); + } + + return builder.build(); + } + + @Override + public List validate(Set configuredFields) { + List errors = new ArrayList<>(); + + if (getCookieBehavior() != null) { + if ((getCookieBehavior() != OriginRequestPolicyCookieBehavior.NONE + && getCookieBehavior() != OriginRequestPolicyCookieBehavior.ALL) + && getCookies().isEmpty()) { + errors.add(new ValidationError( + this, + null, + "'cookies' is required when 'cookie-behavior' is not 'none' or 'all'.")); + } + + if ((getCookieBehavior() == OriginRequestPolicyCookieBehavior.NONE || + getCookieBehavior() == OriginRequestPolicyCookieBehavior.ALL) && !getCookies().isEmpty()) { + errors.add(new ValidationError( + this, + null, + "'cookies' should be empty when 'cookie-behavior' is 'none' or 'all'.")); + } + } + + return errors; + } +} diff --git a/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyFinder.java b/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyFinder.java new file mode 100644 index 000000000..65c41077f --- /dev/null +++ b/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyFinder.java @@ -0,0 +1,102 @@ +/* + * Copyright 2024, Brightspot. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.aws.cloudfront; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import gyro.aws.AwsFinder; +import gyro.core.Type; +import software.amazon.awssdk.services.cloudfront.CloudFrontClient; +import software.amazon.awssdk.services.cloudfront.model.ListOriginRequestPoliciesRequest; +import software.amazon.awssdk.services.cloudfront.model.ListOriginRequestPoliciesResponse; +import software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicy; +import software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicySummary; +import software.amazon.awssdk.services.cloudfront.model.GetOriginRequestPolicyRequest; +import software.amazon.awssdk.services.cloudfront.model.GetOriginRequestPolicyResponse; +import software.amazon.awssdk.services.cloudfront.model.NoSuchOriginRequestPolicyException; + +/** + * Query origin request policy. + * + * Example + * ------- + * + * .. code-block:: gyro + * + * origin-request-policy: $(external-query aws::cloudfront-origin-request-policy { id: '' }) + */ +@Type("cloudfront-origin-request-policy") +public class OriginRequestPolicyFinder extends AwsFinder { + + private String id; + + /** + * The ID of the origin request policy. + */ + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + protected List findAllAws(CloudFrontClient client) { + List cachePolicies = new ArrayList<>(); + + String marker = null; + ListOriginRequestPoliciesResponse response = client.listOriginRequestPolicies( + ListOriginRequestPoliciesRequest.builder().marker(marker).build()); + + if (response.originRequestPolicyList() != null && response.originRequestPolicyList().items() != null) { + cachePolicies.addAll(response.originRequestPolicyList().items().stream() + .map(OriginRequestPolicySummary::originRequestPolicy) + .collect(Collectors.toList())); + } + + return cachePolicies; + } + + @Override + protected List findAws(CloudFrontClient client, Map filters) { + List cachePolicies = new ArrayList<>(); + + if (filters.containsKey("id")) { + try { + GetOriginRequestPolicyResponse response = client.getOriginRequestPolicy(GetOriginRequestPolicyRequest.builder() + .id(filters.get("id")) + .build()); + + if (response.originRequestPolicy() != null) { + cachePolicies.add(response.originRequestPolicy()); + } + + } catch (NoSuchOriginRequestPolicyException e) { + // Ignore + } + + } else { + cachePolicies.addAll(findAllAws(client)); + } + + return cachePolicies; + } +} diff --git a/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyHeadersConfig.java b/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyHeadersConfig.java new file mode 100644 index 000000000..e4e30b4b5 --- /dev/null +++ b/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyHeadersConfig.java @@ -0,0 +1,116 @@ +/* + * Copyright 2024, Brightspot. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.aws.cloudfront; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import gyro.aws.Copyable; +import gyro.core.resource.Diffable; +import gyro.core.resource.Updatable; +import gyro.core.validation.Required; +import gyro.core.validation.ValidStrings; +import gyro.core.validation.ValidationError; +import software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyHeaderBehavior; + +public class OriginRequestPolicyHeadersConfig + extends Diffable + implements Copyable { + + private OriginRequestPolicyHeaderBehavior headerBehavior; + private Set headers; + + /** + * The header behavior for the origin request policy. + */ + @Required + @ValidStrings({"none", "whitelist", "allViewer", "allExcept", "allViewerAndWhitelistCloudFront"}) + public OriginRequestPolicyHeaderBehavior getHeaderBehavior() { + return headerBehavior; + } + + public void setHeaderBehavior(OriginRequestPolicyHeaderBehavior headerBehavior) { + this.headerBehavior = headerBehavior; + } + + /** + * The headers for the origin request policy. + */ + @Updatable + public Set getHeaders() { + if (headers == null) { + headers = new HashSet<>(); + } + + return headers; + } + + public void setHeaders(Set headers) { + this.headers = headers; + } + + @Override + public void copyFrom(software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyHeadersConfig model) { + setHeaderBehavior(model.headerBehavior()); + setHeaders(null); + if (model.headers() != null) { + setHeaders(new HashSet<>(model.headers().items())); + } + } + + @Override + public String primaryKey() { + return ""; + } + + software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyHeadersConfig toOriginRequestPolicyHeadersConfig() { + software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyHeadersConfig.Builder builder = + software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyHeadersConfig.builder() + .headerBehavior(getHeaderBehavior()); + + if (!getHeaders().isEmpty()) { + builder.headers(r -> r.items(getHeaders()).quantity(getHeaders().size())); + } + + return builder.build(); + } + + @Override + public List validate(Set configuredFields) { + List errors = new ArrayList<>(); + + if (getHeaderBehavior() != null) { + if (getHeaderBehavior() != OriginRequestPolicyHeaderBehavior.NONE && getHeaders().isEmpty()) { + errors.add(new ValidationError( + this, + null, + "'headers' is required when 'header-behavior' is not 'none'.")); + } + + if (getHeaderBehavior() == OriginRequestPolicyHeaderBehavior.NONE && !getHeaders().isEmpty()) { + errors.add(new ValidationError( + this, + null, + "'headers' should be empty when 'headers-behavior' is 'none'.")); + } + } + + return errors; + } +} diff --git a/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyQueryStringsConfig.java b/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyQueryStringsConfig.java new file mode 100644 index 000000000..eb8f670ed --- /dev/null +++ b/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyQueryStringsConfig.java @@ -0,0 +1,119 @@ +/* + * Copyright 2024, Brightspot. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.aws.cloudfront; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import gyro.aws.Copyable; +import gyro.core.resource.Diffable; +import gyro.core.resource.Updatable; +import gyro.core.validation.Required; +import gyro.core.validation.ValidStrings; +import gyro.core.validation.ValidationError; +import software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyQueryStringBehavior; + +public class OriginRequestPolicyQueryStringsConfig extends Diffable + implements Copyable { + + private OriginRequestPolicyQueryStringBehavior queryStringBehavior; + private Set queryStrings; + + /** + * The query string behavior for this origin request policy. + */ + @Required + @ValidStrings({"none", "whitelist", "allExcept", "all"}) + public OriginRequestPolicyQueryStringBehavior getQueryStringBehavior() { + return queryStringBehavior; + } + + public void setQueryStringBehavior(OriginRequestPolicyQueryStringBehavior queryStringBehavior) { + this.queryStringBehavior = queryStringBehavior; + } + + /** + * The query strings for this origin request policy. + */ + @Updatable + public Set getQueryStrings() { + if (queryStrings == null) { + queryStrings = new HashSet<>(); + } + + return queryStrings; + } + + public void setQueryStrings(Set queryStrings) { + this.queryStrings = queryStrings; + } + + @Override + public String primaryKey() { + return ""; + } + + @Override + public void copyFrom(software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyQueryStringsConfig model) { + setQueryStringBehavior(model.queryStringBehavior()); + setQueryStrings(null); + if (model.queryStrings() != null) { + setQueryStrings(new HashSet<>(model.queryStrings().items())); + } + } + + software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyQueryStringsConfig toOriginRequestPolicyQueryStringsConfig() { + software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyQueryStringsConfig.Builder builder = + software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicyQueryStringsConfig.builder() + .queryStringBehavior(getQueryStringBehavior()); + + if (!getQueryStrings().isEmpty()) { + builder.queryStrings(r -> r.items(getQueryStrings()).quantity(getQueryStrings().size())); + } + + return builder.build(); + } + + @Override + public List validate(Set configuredFields) { + List errors = new ArrayList<>(); + + if (getQueryStringBehavior() != null) { + if ((getQueryStringBehavior() != OriginRequestPolicyQueryStringBehavior.NONE + && getQueryStringBehavior() != OriginRequestPolicyQueryStringBehavior.ALL) + && getQueryStrings().isEmpty()) { + errors.add(new ValidationError( + this, + null, + "'query-strings' is required when 'query-string-behavior' is not 'none' or 'all'.")); + } + + if ((getQueryStringBehavior() == OriginRequestPolicyQueryStringBehavior.NONE || + getQueryStringBehavior() == OriginRequestPolicyQueryStringBehavior.ALL) && + !getQueryStrings().isEmpty()) { + errors.add(new ValidationError( + this, + null, + "'query-strings' should be empty when 'query-string-behavior' is 'none' or 'all'.")); + } + } + + return errors; + } +} diff --git a/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyResource.java b/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyResource.java new file mode 100644 index 000000000..8d5bdf80b --- /dev/null +++ b/src/main/java/gyro/aws/cloudfront/OriginRequestPolicyResource.java @@ -0,0 +1,192 @@ +/* + * Copyright 2024, Brightspot. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.aws.cloudfront; + +import java.util.Set; + +import gyro.aws.AwsResource; +import gyro.aws.Copyable; +import gyro.core.GyroUI; +import gyro.core.Type; +import gyro.core.resource.Id; +import gyro.core.resource.Output; +import gyro.core.resource.Resource; +import gyro.core.resource.Updatable; +import gyro.core.scope.State; +import gyro.core.validation.Required; +import software.amazon.awssdk.services.cloudfront.CloudFrontClient; +import software.amazon.awssdk.services.cloudfront.model.OriginRequestPolicy; +import software.amazon.awssdk.services.cloudfront.model.GetOriginRequestPolicyResponse; +import software.amazon.awssdk.services.cloudfront.model.NoSuchOriginRequestPolicyException; + +/** + * Create a cloudfront origin request policy. + * + * Example + * ------- + * + * .. code-block:: gyro + * + * aws::cloudfront-origin-request-policy origin-request-policy-example + * origin-request-policy-config + * default-ttl: 3600 + * max-ttl: 86400 + * min-ttl: 0 + * name: "origin-request-policy-example" + * + * key-param + * accept-encoding-brotli: true + * accept-encoding-gzip: true + * + * headers-config + * header-behavior: "whitelist" + * headers: [ + * "example-header1", + * "example-header2" + * ] + * end + * + * query-strings-config + * query-string-behavior: "whitelist" + * query-strings: [ + * "example-query1", + * "example-query2" + * ] + * end + * + * cookies-config + * cookie-behavior: "whitelist" + * cookies: [ + * "example-cookie1", + * "example-cookie2" + * ] + * end + * end + * end + * end + */ +@Type("cloudfront-origin-request-policy") +public class OriginRequestPolicyResource extends AwsResource implements Copyable { + + private OriginRequestPolicyConfig originRequestPolicyConfig; + private String id; + + /** + * The origin request policy configuration. + * + * @subresource gyro.aws.cloudfront.OriginRequestPolicyConfig + */ + @Required + @Updatable + public OriginRequestPolicyConfig getOriginRequestPolicyConfig() { + return originRequestPolicyConfig; + } + + public void setOriginRequestPolicyConfig(OriginRequestPolicyConfig originRequestPolicyConfig) { + this.originRequestPolicyConfig = originRequestPolicyConfig; + } + + /** + * The ID for the origin request policy. + */ + @Output + @Id + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public void copyFrom(OriginRequestPolicy model) { + setId(model.id()); + + setOriginRequestPolicyConfig(null); + if (model.originRequestPolicyConfig() != null) { + OriginRequestPolicyConfig config = newSubresource(OriginRequestPolicyConfig.class); + config.copyFrom(model.originRequestPolicyConfig()); + setOriginRequestPolicyConfig(config); + } + } + + @Override + public boolean refresh() { + + CloudFrontClient client = getCloudFrontClient(); + + try { + GetOriginRequestPolicyResponse originRequestPolicy = client.getOriginRequestPolicy(r -> r.id(getId())); + + copyFrom(originRequestPolicy.originRequestPolicy()); + + return true; + } catch (NoSuchOriginRequestPolicyException ex) { + return false; + } + } + + @Override + public void create(GyroUI ui, State state) throws Exception { + CloudFrontClient client = getCloudFrontClient(); + + OriginRequestPolicy originRequestPolicy = client.createOriginRequestPolicy(r -> r.originRequestPolicyConfig(getOriginRequestPolicyConfig().toOriginRequestPolicyConfig())).originRequestPolicy(); + + setId(originRequestPolicy.id()); + } + + @Override + public void update(GyroUI ui, State state, Resource current, Set changedFieldNames) throws Exception { + CloudFrontClient client = getCloudFrontClient(); + + client.updateOriginRequestPolicy(r -> r + .originRequestPolicyConfig(getOriginRequestPolicyConfig().toOriginRequestPolicyConfig()) + .id(getId()) + .ifMatch(getOriginRequestPolicyEtag(client)) + ); + } + + @Override + public void delete(GyroUI ui, State state) throws Exception { + CloudFrontClient client = getCloudFrontClient(); + + client.deleteOriginRequestPolicy(r -> r.id(getId()).ifMatch(getOriginRequestPolicyEtag(client))); + } + + private CloudFrontClient getCloudFrontClient() { + CloudFrontClient client = createClient( + CloudFrontClient.class, + "us-east-1", + "https://cloudfront.amazonaws.com"); + + return client; + } + + private String getOriginRequestPolicyEtag(CloudFrontClient client) { + String etag = null; + + try { + GetOriginRequestPolicyResponse response = client.getOriginRequestPolicy(r -> r.id(getId())); + etag = response.eTag(); + } catch (NoSuchOriginRequestPolicyException ex) { + // ignore + } + + return etag; + } +}