Upgrade terraform from 0.11.x to 0.12
Signed-off-by: Collin J. Doering <collin@rekahsoft.ca>
This commit is contained in:
parent
1ee07aab1f
commit
9b779ec31b
193
infra/main.tf
193
infra/main.tf
@ -1,4 +1,6 @@
|
|||||||
terraform {
|
terraform {
|
||||||
|
required_version = ">= 0.12"
|
||||||
|
|
||||||
backend "s3" {
|
backend "s3" {
|
||||||
region = "ca-central-1"
|
region = "ca-central-1"
|
||||||
bucket = "rekahsoft-terraform"
|
bucket = "rekahsoft-terraform"
|
||||||
@ -8,12 +10,12 @@ terraform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
provider "aws" {
|
provider "aws" {
|
||||||
region = "${var.region}"
|
region = var.region
|
||||||
version = "~> 2.15"
|
version = "~> 2.15"
|
||||||
|
|
||||||
assume_role = [{
|
assume_role {
|
||||||
role_arn = "${var.workspace_iam_roles[terraform.workspace]}"
|
role_arn = var.workspace_iam_roles[terraform.workspace]
|
||||||
}]
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provider "aws" {
|
provider "aws" {
|
||||||
@ -21,9 +23,9 @@ provider "aws" {
|
|||||||
region = "us-east-1"
|
region = "us-east-1"
|
||||||
version = "~> 2.1"
|
version = "~> 2.1"
|
||||||
|
|
||||||
assume_role = [{
|
assume_role {
|
||||||
role_arn = "${var.workspace_iam_roles[terraform.workspace]}"
|
role_arn = var.workspace_iam_roles[terraform.workspace]
|
||||||
}]
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provider "null" {
|
provider "null" {
|
||||||
@ -42,68 +44,75 @@ provider "template" {
|
|||||||
# Local values to be re-used throughout this template
|
# Local values to be re-used throughout this template
|
||||||
|
|
||||||
locals {
|
locals {
|
||||||
common_tags = "${map(
|
common_tags = {
|
||||||
"Project", "${var.project}",
|
"Project" = var.project
|
||||||
"Environment", "${terraform.workspace}"
|
"Environment" = terraform.workspace
|
||||||
)}"
|
}
|
||||||
cdn_origin_id = "${terraform.workspace}-origin-cdn"
|
|
||||||
www = "${var.enable_naked_domain ? "" : "www."}"
|
|
||||||
subdomain = "${var.subdomain == "" ? "" : "${var.subdomain}."}"
|
|
||||||
naked_domain = "${local.subdomain}${var.dns_apex}"
|
|
||||||
domain = "${local.www}${local.naked_domain}"
|
|
||||||
project_env = "${var.project}-${terraform.workspace}"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
cdn_origin_id = "${terraform.workspace}-origin-cdn"
|
||||||
|
www = var.enable_naked_domain ? "" : "www."
|
||||||
|
subdomain = var.subdomain == "" ? "" : "${var.subdomain}."
|
||||||
|
naked_domain = "${local.subdomain}${var.dns_apex}"
|
||||||
|
domain = "${local.www}${local.naked_domain}"
|
||||||
|
project_env = "${var.project}-${terraform.workspace}"
|
||||||
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
# Data Sources
|
# Data Sources
|
||||||
|
|
||||||
data "template_file" "s3_origin_policy" {
|
data "template_file" "s3_origin_policy" {
|
||||||
template = "${file("templates/s3_origin_policy.json")}"
|
template = file("templates/s3_origin_policy.json")
|
||||||
|
|
||||||
vars {
|
vars = {
|
||||||
bucket_arn = "${aws_s3_bucket.static.arn}"
|
bucket_arn = aws_s3_bucket.static.arn
|
||||||
user_arn = "${aws_iam_user.app_deploy.arn}"
|
user_arn = aws_iam_user.app_deploy.arn
|
||||||
cloudfront_arn = "${aws_cloudfront_origin_access_identity.origin_access_identity.iam_arn}"
|
cloudfront_arn = aws_cloudfront_origin_access_identity.origin_access_identity.iam_arn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data "aws_route53_zone" "external" {
|
data "aws_route53_zone" "external" {
|
||||||
name = "${var.dns_apex}."
|
name = "${var.dns_apex}."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Resources
|
# Resources
|
||||||
|
|
||||||
resource "aws_acm_certificate" "cert" {
|
resource "aws_acm_certificate" "cert" {
|
||||||
domain_name = "${local.domain}"
|
domain_name = local.domain
|
||||||
subject_alternative_names = "${compact(list("${var.enable_naked_domain}" ? "" : "${local.naked_domain}"))}"
|
subject_alternative_names = compact([var.enable_naked_domain ? "" : local.naked_domain])
|
||||||
validation_method = "DNS"
|
validation_method = "DNS"
|
||||||
tags = "${local.common_tags}"
|
tags = local.common_tags
|
||||||
|
|
||||||
provider = "aws.us_east_1"
|
provider = aws.us_east_1
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_route53_record" "cert_validation" {
|
resource "aws_route53_record" "cert_validation" {
|
||||||
count = "${1 + "${var.enable_naked_domain ? 0 : 1}"}"
|
count = 1 + (var.enable_naked_domain ? 0 : 1)
|
||||||
|
|
||||||
zone_id = "${data.aws_route53_zone.external.id}"
|
zone_id = data.aws_route53_zone.external.id
|
||||||
name = "${lookup(aws_acm_certificate.cert.domain_validation_options[count.index], "resource_record_name")}"
|
name = aws_acm_certificate.cert.domain_validation_options[count.index]["resource_record_name"]
|
||||||
type = "${lookup(aws_acm_certificate.cert.domain_validation_options[count.index], "resource_record_type")}"
|
type = aws_acm_certificate.cert.domain_validation_options[count.index]["resource_record_type"]
|
||||||
ttl = 60
|
ttl = 60
|
||||||
records = ["${lookup(aws_acm_certificate.cert.domain_validation_options[count.index], "resource_record_value")}"]
|
# TF-UPGRADE-TODO: In Terraform v0.10 and earlier, it was sometimes necessary to
|
||||||
|
# force an interpolation expression to be interpreted as a list by wrapping it
|
||||||
|
# in an extra set of list brackets. That form was supported for compatibilty in
|
||||||
|
# v0.11, but is no longer supported in Terraform v0.12.
|
||||||
|
#
|
||||||
|
# If the expression in the following list itself returns a list, remove the
|
||||||
|
# brackets to avoid interpretation as a list of lists. If the expression
|
||||||
|
# returns a single list item then leave it as-is and remove this TODO comment.
|
||||||
|
records = [aws_acm_certificate.cert.domain_validation_options[count.index]["resource_record_value"]]
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_acm_certificate_validation" "cert" {
|
resource "aws_acm_certificate_validation" "cert" {
|
||||||
certificate_arn = "${aws_acm_certificate.cert.arn}"
|
certificate_arn = aws_acm_certificate.cert.arn
|
||||||
validation_record_fqdns = ["${aws_route53_record.cert_validation.*.fqdn}"]
|
validation_record_fqdns = aws_route53_record.cert_validation.*.fqdn
|
||||||
|
|
||||||
provider = "aws.us_east_1"
|
provider = aws.us_east_1
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_s3_bucket" "static" {
|
resource "aws_s3_bucket" "static" {
|
||||||
bucket_prefix = "${local.project_env}"
|
bucket_prefix = local.project_env
|
||||||
acl = "private"
|
acl = "private"
|
||||||
|
|
||||||
website {
|
website {
|
||||||
@ -111,71 +120,71 @@ resource "aws_s3_bucket" "static" {
|
|||||||
error_document = "error.html"
|
error_document = "error.html"
|
||||||
}
|
}
|
||||||
|
|
||||||
tags = "${local.common_tags}"
|
tags = local.common_tags
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_s3_bucket" "static_redirect" {
|
resource "aws_s3_bucket" "static_redirect" {
|
||||||
count = "${var.enable_naked_domain ? 0 : 1}"
|
count = var.enable_naked_domain ? 0 : 1
|
||||||
|
|
||||||
bucket_prefix = "${local.project_env}"
|
bucket_prefix = local.project_env
|
||||||
acl = "private"
|
acl = "private"
|
||||||
|
|
||||||
website {
|
website {
|
||||||
redirect_all_requests_to = "https://${local.domain}"
|
redirect_all_requests_to = "https://${local.domain}"
|
||||||
}
|
}
|
||||||
|
|
||||||
tags = "${local.common_tags}"
|
tags = local.common_tags
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_s3_bucket" "static_logs" {
|
resource "aws_s3_bucket" "static_logs" {
|
||||||
bucket_prefix = "${local.project_env}"
|
bucket_prefix = local.project_env
|
||||||
acl = "private"
|
acl = "private"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "random_string" "app_deploy_username" {
|
resource "random_string" "app_deploy_username" {
|
||||||
length = 16
|
length = 16
|
||||||
special = true
|
special = true
|
||||||
override_special = "_+=,.@-"
|
override_special = "_+=,.@-"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_iam_user" "app_deploy" {
|
resource "aws_iam_user" "app_deploy" {
|
||||||
name = "${random_string.app_deploy_username.result}"
|
name = random_string.app_deploy_username.result
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_iam_access_key" "app_deploy" {
|
resource "aws_iam_access_key" "app_deploy" {
|
||||||
user = "${aws_iam_user.app_deploy.name}"
|
user = aws_iam_user.app_deploy.name
|
||||||
# pgp_key = "keybase:some_person_that_exists"
|
# pgp_key = "keybase:some_person_that_exists"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_route53_record" "static" {
|
resource "aws_route53_record" "static" {
|
||||||
zone_id = "${data.aws_route53_zone.external.zone_id}"
|
zone_id = data.aws_route53_zone.external.zone_id
|
||||||
name = "${local.domain}."
|
name = "${local.domain}."
|
||||||
type = "A"
|
type = "A"
|
||||||
|
|
||||||
alias {
|
alias {
|
||||||
name = "${aws_cloudfront_distribution.cdn.domain_name}"
|
name = aws_cloudfront_distribution.cdn.domain_name
|
||||||
zone_id = "${aws_cloudfront_distribution.cdn.hosted_zone_id}"
|
zone_id = aws_cloudfront_distribution.cdn.hosted_zone_id
|
||||||
evaluate_target_health = true
|
evaluate_target_health = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_route53_record" "static_redirect" {
|
resource "aws_route53_record" "static_redirect" {
|
||||||
count = "${var.enable_naked_domain ? 0 : 1}"
|
count = var.enable_naked_domain ? 0 : 1
|
||||||
|
|
||||||
zone_id = "${data.aws_route53_zone.external.zone_id}"
|
zone_id = data.aws_route53_zone.external.zone_id
|
||||||
name = "${local.naked_domain}."
|
name = "${local.naked_domain}."
|
||||||
type = "A"
|
type = "A"
|
||||||
|
|
||||||
alias {
|
alias {
|
||||||
name = "${aws_cloudfront_distribution.cdn_redirect.domain_name}"
|
name = aws_cloudfront_distribution.cdn_redirect[0].domain_name
|
||||||
zone_id = "${aws_cloudfront_distribution.cdn_redirect.hosted_zone_id}"
|
zone_id = aws_cloudfront_distribution.cdn_redirect[0].hosted_zone_id
|
||||||
evaluate_target_health = true
|
evaluate_target_health = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_s3_bucket_policy" "static_policy" {
|
resource "aws_s3_bucket_policy" "static_policy" {
|
||||||
bucket = "${aws_s3_bucket.static.id}"
|
bucket = aws_s3_bucket.static.id
|
||||||
policy = "${data.template_file.s3_origin_policy.rendered}"
|
policy = data.template_file.s3_origin_policy.rendered
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_cloudfront_origin_access_identity" "origin_access_identity" {
|
resource "aws_cloudfront_origin_access_identity" "origin_access_identity" {
|
||||||
@ -185,11 +194,11 @@ resource "aws_cloudfront_origin_access_identity" "origin_access_identity" {
|
|||||||
resource "aws_cloudfront_distribution" "cdn" {
|
resource "aws_cloudfront_distribution" "cdn" {
|
||||||
# Static file origin
|
# Static file origin
|
||||||
origin {
|
origin {
|
||||||
domain_name = "${aws_s3_bucket.static.bucket_regional_domain_name}"
|
domain_name = aws_s3_bucket.static.bucket_regional_domain_name
|
||||||
origin_id = "${local.cdn_origin_id}"
|
origin_id = local.cdn_origin_id
|
||||||
|
|
||||||
s3_origin_config {
|
s3_origin_config {
|
||||||
origin_access_identity = "${aws_cloudfront_origin_access_identity.origin_access_identity.cloudfront_access_identity_path}"
|
origin_access_identity = aws_cloudfront_origin_access_identity.origin_access_identity.cloudfront_access_identity_path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,22 +210,30 @@ resource "aws_cloudfront_distribution" "cdn" {
|
|||||||
# Return index.html for any route that is not found
|
# Return index.html for any route that is not found
|
||||||
custom_error_response {
|
custom_error_response {
|
||||||
error_caching_min_ttl = 0
|
error_caching_min_ttl = 0
|
||||||
error_code = 403
|
error_code = 403
|
||||||
response_code = 200
|
response_code = 200
|
||||||
response_page_path = "/index.html"
|
response_page_path = "/index.html"
|
||||||
}
|
}
|
||||||
|
|
||||||
logging_config {
|
logging_config {
|
||||||
include_cookies = false
|
include_cookies = false
|
||||||
bucket = "${aws_s3_bucket.static_logs.bucket_domain_name}"
|
bucket = aws_s3_bucket.static_logs.bucket_domain_name
|
||||||
}
|
}
|
||||||
|
|
||||||
aliases = ["${local.domain}"]
|
# TF-UPGRADE-TODO: In Terraform v0.10 and earlier, it was sometimes necessary to
|
||||||
|
# force an interpolation expression to be interpreted as a list by wrapping it
|
||||||
|
# in an extra set of list brackets. That form was supported for compatibilty in
|
||||||
|
# v0.11, but is no longer supported in Terraform v0.12.
|
||||||
|
#
|
||||||
|
# If the expression in the following list itself returns a list, remove the
|
||||||
|
# brackets to avoid interpretation as a list of lists. If the expression
|
||||||
|
# returns a single list item then leave it as-is and remove this TODO comment.
|
||||||
|
aliases = [local.domain]
|
||||||
|
|
||||||
default_cache_behavior {
|
default_cache_behavior {
|
||||||
allowed_methods = ["GET", "HEAD", "OPTIONS"]
|
allowed_methods = ["GET", "HEAD", "OPTIONS"]
|
||||||
cached_methods = ["GET", "HEAD", "OPTIONS"]
|
cached_methods = ["GET", "HEAD", "OPTIONS"]
|
||||||
target_origin_id = "${local.cdn_origin_id}"
|
target_origin_id = local.cdn_origin_id
|
||||||
|
|
||||||
forwarded_values {
|
forwarded_values {
|
||||||
query_string = false
|
query_string = false
|
||||||
@ -237,11 +254,11 @@ resource "aws_cloudfront_distribution" "cdn" {
|
|||||||
path_pattern = "index.html"
|
path_pattern = "index.html"
|
||||||
allowed_methods = ["GET", "HEAD", "OPTIONS"]
|
allowed_methods = ["GET", "HEAD", "OPTIONS"]
|
||||||
cached_methods = ["GET", "HEAD", "OPTIONS"]
|
cached_methods = ["GET", "HEAD", "OPTIONS"]
|
||||||
target_origin_id = "${local.cdn_origin_id}"
|
target_origin_id = local.cdn_origin_id
|
||||||
|
|
||||||
forwarded_values {
|
forwarded_values {
|
||||||
query_string = false
|
query_string = false
|
||||||
headers = ["Origin"]
|
headers = ["Origin"]
|
||||||
cookies {
|
cookies {
|
||||||
forward = "none"
|
forward = "none"
|
||||||
}
|
}
|
||||||
@ -262,25 +279,25 @@ resource "aws_cloudfront_distribution" "cdn" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tags = "${local.common_tags}"
|
tags = local.common_tags
|
||||||
|
|
||||||
viewer_certificate {
|
viewer_certificate {
|
||||||
acm_certificate_arn = "${aws_acm_certificate_validation.cert.certificate_arn}"
|
acm_certificate_arn = aws_acm_certificate_validation.cert.certificate_arn
|
||||||
ssl_support_method = "sni-only"
|
ssl_support_method = "sni-only"
|
||||||
minimum_protocol_version = "TLSv1.1_2016"
|
minimum_protocol_version = "TLSv1.1_2016"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_cloudfront_distribution" "cdn_redirect" {
|
resource "aws_cloudfront_distribution" "cdn_redirect" {
|
||||||
count = "${var.enable_naked_domain ? 0 : 1}"
|
count = var.enable_naked_domain ? 0 : 1
|
||||||
|
|
||||||
# Static file origin
|
# Static file origin
|
||||||
origin {
|
origin {
|
||||||
domain_name = "${aws_s3_bucket.static_redirect.id}.${aws_s3_bucket.static_redirect.website_domain}"
|
domain_name = "${aws_s3_bucket.static_redirect[0].id}.${aws_s3_bucket.static_redirect[0].website_domain}"
|
||||||
origin_id = "${local.cdn_origin_id}"
|
origin_id = local.cdn_origin_id
|
||||||
|
|
||||||
custom_origin_config {
|
custom_origin_config {
|
||||||
http_port = 80
|
http_port = 80
|
||||||
https_port = 443
|
https_port = 443
|
||||||
|
|
||||||
origin_ssl_protocols = ["TLSv1.1", "TLSv1.2"]
|
origin_ssl_protocols = ["TLSv1.1", "TLSv1.2"]
|
||||||
@ -288,21 +305,29 @@ resource "aws_cloudfront_distribution" "cdn_redirect" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enabled = true
|
enabled = true
|
||||||
is_ipv6_enabled = true
|
is_ipv6_enabled = true
|
||||||
comment = "CDN redirect for ${var.project} (environment ${terraform.workspace})"
|
comment = "CDN redirect for ${var.project} (environment ${terraform.workspace})"
|
||||||
|
|
||||||
logging_config {
|
logging_config {
|
||||||
include_cookies = false
|
include_cookies = false
|
||||||
bucket = "${aws_s3_bucket.static_logs.bucket_domain_name}"
|
bucket = aws_s3_bucket.static_logs.bucket_domain_name
|
||||||
}
|
}
|
||||||
|
|
||||||
aliases = ["${local.naked_domain}"]
|
# TF-UPGRADE-TODO: In Terraform v0.10 and earlier, it was sometimes necessary to
|
||||||
|
# force an interpolation expression to be interpreted as a list by wrapping it
|
||||||
|
# in an extra set of list brackets. That form was supported for compatibilty in
|
||||||
|
# v0.11, but is no longer supported in Terraform v0.12.
|
||||||
|
#
|
||||||
|
# If the expression in the following list itself returns a list, remove the
|
||||||
|
# brackets to avoid interpretation as a list of lists. If the expression
|
||||||
|
# returns a single list item then leave it as-is and remove this TODO comment.
|
||||||
|
aliases = [local.naked_domain]
|
||||||
|
|
||||||
default_cache_behavior {
|
default_cache_behavior {
|
||||||
allowed_methods = ["GET", "HEAD", "OPTIONS"]
|
allowed_methods = ["GET", "HEAD", "OPTIONS"]
|
||||||
cached_methods = ["GET", "HEAD", "OPTIONS"]
|
cached_methods = ["GET", "HEAD", "OPTIONS"]
|
||||||
target_origin_id = "${local.cdn_origin_id}"
|
target_origin_id = local.cdn_origin_id
|
||||||
|
|
||||||
forwarded_values {
|
forwarded_values {
|
||||||
query_string = false
|
query_string = false
|
||||||
@ -326,10 +351,10 @@ resource "aws_cloudfront_distribution" "cdn_redirect" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tags = "${local.common_tags}"
|
tags = local.common_tags
|
||||||
|
|
||||||
viewer_certificate {
|
viewer_certificate {
|
||||||
acm_certificate_arn = "${aws_acm_certificate_validation.cert.certificate_arn}"
|
acm_certificate_arn = aws_acm_certificate_validation.cert.certificate_arn
|
||||||
ssl_support_method = "sni-only"
|
ssl_support_method = "sni-only"
|
||||||
minimum_protocol_version = "TLSv1.1_2016"
|
minimum_protocol_version = "TLSv1.1_2016"
|
||||||
}
|
}
|
||||||
@ -338,7 +363,7 @@ resource "aws_cloudfront_distribution" "cdn_redirect" {
|
|||||||
resource "null_resource" "deploy_app" {
|
resource "null_resource" "deploy_app" {
|
||||||
provisioner "local-exec" {
|
provisioner "local-exec" {
|
||||||
interpreter = ["bash", "-c"]
|
interpreter = ["bash", "-c"]
|
||||||
command = <<SCRIPT
|
command = <<SCRIPT
|
||||||
: Create temporary aws config and credentials files
|
: Create temporary aws config and credentials files
|
||||||
export AWS_CONFIG_FILE=$(mktemp);
|
export AWS_CONFIG_FILE=$(mktemp);
|
||||||
export AWS_SHARED_CREDENTIALS_FILE=$(mktemp);
|
export AWS_SHARED_CREDENTIALS_FILE=$(mktemp);
|
||||||
@ -354,5 +379,7 @@ aws --profile ${aws_iam_user.app_deploy.name} s3 sync --delete ../_site s3://${a
|
|||||||
: Cleanup temporary aws config and credentials files
|
: Cleanup temporary aws config and credentials files
|
||||||
rm $${AWS_CONFIG_FILE} $${AWS_SHARED_CREDENTIALS_FILE};
|
rm $${AWS_CONFIG_FILE} $${AWS_SHARED_CREDENTIALS_FILE};
|
||||||
SCRIPT
|
SCRIPT
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
output "s3_bucket_static" {
|
output "s3_bucket_static" {
|
||||||
value = "${aws_s3_bucket.static.id}"
|
value = aws_s3_bucket.static.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,8 @@ variable "project" {
|
|||||||
default = "blog-rekahsoft-ca"
|
default = "blog-rekahsoft-ca"
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "dns_apex" {}
|
variable "dns_apex" {
|
||||||
|
}
|
||||||
|
|
||||||
variable "subdomain" {
|
variable "subdomain" {
|
||||||
default = ""
|
default = ""
|
||||||
@ -23,3 +24,4 @@ variable "subdomain" {
|
|||||||
variable "enable_naked_domain" {
|
variable "enable_naked_domain" {
|
||||||
default = false
|
default = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user