Merge pull request 'main' (#4) from francesco.mangiacrapa/infrastructure-as-code:main into main
Reviewed-on: #4
This commit is contained in:
commit
ca4a530a38
|
@ -0,0 +1,24 @@
|
||||||
|
# This file is maintained automatically by "terraform init".
|
||||||
|
# Manual edits may be lost in future updates.
|
||||||
|
|
||||||
|
provider "registry.terraform.io/terraform-provider-openstack/openstack" {
|
||||||
|
version = "1.53.0"
|
||||||
|
constraints = "~> 1.53.0"
|
||||||
|
hashes = [
|
||||||
|
"h1:YLGvYkSuagyP5orUTyKNK+JhzS17EFTUDpZ5R5/fFv4=",
|
||||||
|
"zh:09da7ca98ffd3de7b9ce36c4c13446212a6e763ba1162be71b50f95d453cb68e",
|
||||||
|
"zh:14041bcbb87312411d88612056ed185650bfd01284b8ea0761ce8105a331708e",
|
||||||
|
"zh:35bf4c788fdbc17c8e40ebc7b33c7de4b45a2fa2efaa657b10f0e3bd37c9627f",
|
||||||
|
"zh:46ede8ef4cfa12d654c538afc1e1ec34a1f3e8eb4e986ee23dceae398b7176a6",
|
||||||
|
"zh:59675734990dab1e8d87997853ea75e8104bba730b3f5a7146ac735540c9d6bf",
|
||||||
|
"zh:6de52428849806498670e827b54810be7510a2a79449602c1aede4235a0ec036",
|
||||||
|
"zh:78b2a20601272afceffac8f8ca78a6b647b84196c0dd8dc710fae297f6be15a4",
|
||||||
|
"zh:7c41ed3a4fac09677e676ecf9f9edd1e38eef449e656cb01a848d2c799c6de8f",
|
||||||
|
"zh:852800228f4118a4aa6cfaa4468b851247cbed6f037fd204f08de69eb1edc149",
|
||||||
|
"zh:86d618e7f9a07d978b8bc4b190be350a00de64ec535f9c8f5dfe133542a55483",
|
||||||
|
"zh:963a9e72b66d8bcf43de9b14a674ae3ca3719ce2f829217f7a65b66fc3773397",
|
||||||
|
"zh:a8e72ab67795071bda61f99a6de3d2d40122fb51971768fd75e1324abe874ced",
|
||||||
|
"zh:ce1890cf3af17d569af3bc7673cec0a8f78e6f5d701767593f3d29c551f44848",
|
||||||
|
"zh:e6f1b96eb684f527a47f71923f268c86a36d7894751b31ee9e726d7502a639cd",
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Define required providers
|
||||||
|
terraform {
|
||||||
|
required_version = ">= 0.14.0"
|
||||||
|
required_providers {
|
||||||
|
openstack = {
|
||||||
|
source = "terraform-provider-openstack/openstack"
|
||||||
|
version = "~> 1.53.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "terraform_remote_state" "privnet_dns_router" {
|
||||||
|
backend = "local"
|
||||||
|
|
||||||
|
config = {
|
||||||
|
path = "../project-setup/terraform.tfstate"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module "smartgears_service_generic" {
|
||||||
|
source = "../../modules/generic_smartgears_service"
|
||||||
|
|
||||||
|
smartgears_service_instances_map = {
|
||||||
|
geoportal_service = {
|
||||||
|
name = "geoportal-cms",
|
||||||
|
description = "The Geoportal instance",
|
||||||
|
flavor = "m1.medium",
|
||||||
|
networks = ["d4s-dev-cloud-main", "postgresql-srv-net"],
|
||||||
|
security_groups = ["default", "http and https from the load balancers"]
|
||||||
|
block_device_uuid = "7ed6a2cd-2b07-482e-8ce4-f018dff16c89" #ubuntu_18_04.uuid of DEV
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
provider "openstack" {
|
||||||
|
cloud = "d4s-dev"
|
||||||
|
}
|
|
@ -16,15 +16,69 @@ variable "geoserver_instances_map" {
|
||||||
vol_data_size = string
|
vol_data_size = string
|
||||||
}))
|
}))
|
||||||
default = {
|
default = {
|
||||||
geona = { name = "geoserver-geona", description = "Geoserver geona instance", flavor = "m1.xlarge", vol_data_name = "geoserver-geona_data_volume", vol_data_size = "50" }
|
geona = {
|
||||||
esquiline = { name = "geoserver-esquiline", description = "Geoserver esquiline instance", flavor = "m2.small", vol_data_name = "geoserver-esquiline_data_volume", vol_data_size = "20" }
|
name = "geoserver-geona",
|
||||||
ariadne = { name = "geoserver-ariadne", description = "Geoserver ariadne instance", flavor = "m2.small", vol_data_name = "geoserver-ariadne_data_volume", vol_data_size = "20" }
|
description = "Geoserver geona instance",
|
||||||
grsf = { name = "geoserver-grsf", description = "Geoserver grsf instance", flavor = "m1.large", vol_data_name = "geoserver-grsf_data_volume", vol_data_size = "40" }
|
flavor = "m1.xlarge",
|
||||||
protectedareaimpactmaps = { name = "geoserver-protectedareaimpactmaps", description = "Geoserver protectedareaimpactmaps instance", flavor = "c1.large", vol_data_name = "geoserver-protectedareaimpactmaps_data_volume", vol_data_size = "70" }
|
vol_data_name = "geoserver-geona_data_volume",
|
||||||
sdi-lab = { name = "geoserver-sdi-lab", description = "Geoserver sdi-lab instance", flavor = "m1.large", vol_data_name = "geoserver-sdi-lab_data_volume", vol_data_size = "100" }
|
vol_data_size = "50"
|
||||||
tunaatlas = { name = "geoserver-tunaatlas", description = "Geoserver tunaatlas instance", flavor = "m1.large", vol_data_name = "geoserver-tunaatlas_data_volume", vol_data_size = "60" }
|
}
|
||||||
wecafc-firms = { name = "geoserver-wecafc-firms", description = "Geoserver wecafc-firms instance", flavor = "m1.large", vol_data_name = "geoserver-wecafc-firms_data_volume", vol_data_size = "40" }
|
esquiline = {
|
||||||
aquacultureatlas = { name = "geoserver-aquacultureatlas", description = "Geoserver aquacultureatlas instance", flavor = "m1.large", vol_data_name = "geoserver-aquacultureatlas_data_volume", vol_data_size = "50" }
|
name = "geoserver-esquiline",
|
||||||
|
description = "Geoserver esquiline instance",
|
||||||
|
flavor = "m2.small",
|
||||||
|
vol_data_name = "geoserver-esquiline_data_volume",
|
||||||
|
vol_data_size = "20"
|
||||||
|
}
|
||||||
|
ariadne = {
|
||||||
|
name = "geoserver-ariadne",
|
||||||
|
description = "Geoserver ariadne instance",
|
||||||
|
flavor = "m2.small",
|
||||||
|
vol_data_name = "geoserver-ariadne_data_volume",
|
||||||
|
vol_data_size = "20"
|
||||||
|
}
|
||||||
|
grsf = {
|
||||||
|
name = "geoserver-grsf",
|
||||||
|
description = "Geoserver grsf instance",
|
||||||
|
flavor = "m1.large",
|
||||||
|
vol_data_name = "geoserver-grsf_data_volume",
|
||||||
|
vol_data_size = "40"
|
||||||
|
}
|
||||||
|
protectedareaimpactmaps = {
|
||||||
|
name = "geoserver-protectedareaimpactmaps",
|
||||||
|
description = "Geoserver protectedareaimpactmaps instance",
|
||||||
|
flavor = "c1.large",
|
||||||
|
vol_data_name = "geoserver-protectedareaimpactmaps_data_volume",
|
||||||
|
vol_data_size = "70"
|
||||||
|
}
|
||||||
|
sdi-lab = {
|
||||||
|
name = "geoserver-sdi-lab",
|
||||||
|
description = "Geoserver sdi-lab instance",
|
||||||
|
flavor = "m1.large",
|
||||||
|
vol_data_name = "geoserver-sdi-lab_data_volume",
|
||||||
|
vol_data_size = "100"
|
||||||
|
}
|
||||||
|
tunaatlas = {
|
||||||
|
name = "geoserver-tunaatlas",
|
||||||
|
description = "Geoserver tunaatlas instance",
|
||||||
|
flavor = "m1.large",
|
||||||
|
vol_data_name = "geoserver-tunaatlas_data_volume",
|
||||||
|
vol_data_size = "60"
|
||||||
|
}
|
||||||
|
wecafc-firms = {
|
||||||
|
name = "geoserver-wecafc-firms",
|
||||||
|
description = "Geoserver wecafc-firms instance",
|
||||||
|
flavor = "m1.large",
|
||||||
|
vol_data_name = "geoserver-wecafc-firms_data_volume",
|
||||||
|
vol_data_size = "40"
|
||||||
|
}
|
||||||
|
aquacultureatlas = {
|
||||||
|
name = "geoserver-aquacultureatlas",
|
||||||
|
description = "Geoserver aquacultureatlas instance",
|
||||||
|
flavor = "m1.large",
|
||||||
|
vol_data_name = "geoserver-aquacultureatlas_data_volume",
|
||||||
|
vol_data_size = "50"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
# This file is maintained automatically by "terraform init".
|
||||||
|
# Manual edits may be lost in future updates.
|
||||||
|
|
||||||
|
provider "registry.terraform.io/terraform-provider-openstack/openstack" {
|
||||||
|
version = "1.53.0"
|
||||||
|
constraints = "~> 1.53.0"
|
||||||
|
hashes = [
|
||||||
|
"h1:YLGvYkSuagyP5orUTyKNK+JhzS17EFTUDpZ5R5/fFv4=",
|
||||||
|
"zh:09da7ca98ffd3de7b9ce36c4c13446212a6e763ba1162be71b50f95d453cb68e",
|
||||||
|
"zh:14041bcbb87312411d88612056ed185650bfd01284b8ea0761ce8105a331708e",
|
||||||
|
"zh:35bf4c788fdbc17c8e40ebc7b33c7de4b45a2fa2efaa657b10f0e3bd37c9627f",
|
||||||
|
"zh:46ede8ef4cfa12d654c538afc1e1ec34a1f3e8eb4e986ee23dceae398b7176a6",
|
||||||
|
"zh:59675734990dab1e8d87997853ea75e8104bba730b3f5a7146ac735540c9d6bf",
|
||||||
|
"zh:6de52428849806498670e827b54810be7510a2a79449602c1aede4235a0ec036",
|
||||||
|
"zh:78b2a20601272afceffac8f8ca78a6b647b84196c0dd8dc710fae297f6be15a4",
|
||||||
|
"zh:7c41ed3a4fac09677e676ecf9f9edd1e38eef449e656cb01a848d2c799c6de8f",
|
||||||
|
"zh:852800228f4118a4aa6cfaa4468b851247cbed6f037fd204f08de69eb1edc149",
|
||||||
|
"zh:86d618e7f9a07d978b8bc4b190be350a00de64ec535f9c8f5dfe133542a55483",
|
||||||
|
"zh:963a9e72b66d8bcf43de9b14a674ae3ca3719ce2f829217f7a65b66fc3773397",
|
||||||
|
"zh:a8e72ab67795071bda61f99a6de3d2d40122fb51971768fd75e1324abe874ced",
|
||||||
|
"zh:ce1890cf3af17d569af3bc7673cec0a8f78e6f5d701767593f3d29c551f44848",
|
||||||
|
"zh:e6f1b96eb684f527a47f71923f268c86a36d7894751b31ee9e726d7502a639cd",
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Define required providers
|
||||||
|
terraform {
|
||||||
|
required_version = ">= 0.14.0"
|
||||||
|
required_providers {
|
||||||
|
openstack = {
|
||||||
|
source = "terraform-provider-openstack/openstack"
|
||||||
|
version = "~> 1.53.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "terraform_remote_state" "privnet_dns_router" {
|
||||||
|
backend = "local"
|
||||||
|
|
||||||
|
config = {
|
||||||
|
path = "../project-setup/terraform.tfstate"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module "smartgears_service_generic" {
|
||||||
|
source = "../../modules/generic_smartgears_service"
|
||||||
|
|
||||||
|
smartgears_service_instances_map = {
|
||||||
|
uri_resolver_service_i1 = {
|
||||||
|
name = "data",
|
||||||
|
description = "The data instance",
|
||||||
|
flavor = "m1.medium",
|
||||||
|
networks = ["d4s-dev-cloud-main"],
|
||||||
|
security_groups = ["default", "http and https from the load balancers"]
|
||||||
|
block_device_uuid = "7ed6a2cd-2b07-482e-8ce4-f018dff16c89" #ubuntu_18_04.uuid of DEV
|
||||||
|
},
|
||||||
|
# URI-Resolver instance 2
|
||||||
|
uri_resolver_service_i2 = {
|
||||||
|
name = "data1",
|
||||||
|
description = "The data1 instance",
|
||||||
|
flavor = "m1.medium",
|
||||||
|
networks = ["d4s-dev-cloud-main"],
|
||||||
|
security_groups = ["default", "http and https from the load balancers"]
|
||||||
|
block_device_uuid = "7ed6a2cd-2b07-482e-8ce4-f018dff16c89" #ubuntu_18_04.uuid of DEV
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
provider "openstack" {
|
||||||
|
cloud = "d4s-dev"
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Generic smartgears_service instance
|
||||||
|
|
||||||
|
module "ssh_settings" {
|
||||||
|
source = "../../modules/ssh-key-ref"
|
||||||
|
}
|
||||||
|
|
||||||
|
module "common_variables" {
|
||||||
|
source = "../../modules/common_variables"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "openstack_compute_instance_v2" "smartgears_service" {
|
||||||
|
for_each = var.smartgears_service_instances_map
|
||||||
|
name = each.value.name
|
||||||
|
availability_zone_hints = module.common_variables.availability_zone_no_gpu_name
|
||||||
|
flavor_name = each.value.flavor
|
||||||
|
key_pair = module.ssh_settings.ssh_key_name
|
||||||
|
security_groups = each.value.security_groups
|
||||||
|
block_device {
|
||||||
|
uuid = each.value.block_device_uuid
|
||||||
|
source_type = "image"
|
||||||
|
volume_size = 10
|
||||||
|
boot_index = 0
|
||||||
|
destination_type = "volume"
|
||||||
|
delete_on_termination = false
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic "network" {
|
||||||
|
for_each = each.value.networks
|
||||||
|
content {
|
||||||
|
name = network.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
user_data = file("${module.common_variables.ubuntu1804_data_file}")
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
output "smartgears_service_instances_map" {
|
||||||
|
value = var.smartgears_service_instances_map
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Define required providers
|
||||||
|
terraform {
|
||||||
|
required_version = ">= 0.14.0"
|
||||||
|
required_providers {
|
||||||
|
openstack = {
|
||||||
|
source = "terraform-provider-openstack/openstack"
|
||||||
|
version = "~> 1.53.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
#Default smartgears_service is EMPTY. Override it to create a proper smartegears plan
|
||||||
|
variable "smartgears_service_instances_map" {
|
||||||
|
type = map(object({
|
||||||
|
name = string
|
||||||
|
description = string
|
||||||
|
flavor = string
|
||||||
|
networks = list(string)
|
||||||
|
security_groups = list(string)
|
||||||
|
block_device_uuid = string
|
||||||
|
}))
|
||||||
|
default = {
|
||||||
|
smartgears_service = { name = "", description = "", flavor = "", networks = [], security_groups = [], block_device_uuid = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
#This file must be renamed as 'ssh-key-ref-outputs.tf'
|
||||||
|
#replace the placeholders {YOUR_PRIVATE_KEYNAME} (without .pb) and {YOUR_KEYNAME} with proper values
|
||||||
|
|
||||||
|
output "ssh_key_file" {
|
||||||
|
value = "~/.ssh/{YOUR_PRIVATE_KEYNAME}"
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
output "ssh_key_name" {
|
||||||
|
value = "{YOUR_KEYNAME}"
|
||||||
|
sensitive = false
|
||||||
|
}
|
|
@ -1,27 +1,27 @@
|
||||||
# TimeScaleDB shared server
|
# TimeScaleDB shared server
|
||||||
# Network
|
# Network
|
||||||
resource "openstack_networking_network_v2" "timescaledb_net" {
|
resource "openstack_networking_network_v2" "timescaledb_net" {
|
||||||
name = var.timescaledb_net.network_name
|
name = var.timescaledb_net.network_name
|
||||||
admin_state_up = "true"
|
admin_state_up = "true"
|
||||||
external = "false"
|
external = "false"
|
||||||
description = var.timescaledb_net.network_description
|
description = var.timescaledb_net.network_description
|
||||||
dns_domain = var.dns_zone.zone_name
|
dns_domain = var.dns_zone.zone_name
|
||||||
mtu = var.mtu_size
|
mtu = var.mtu_size
|
||||||
port_security_enabled = true
|
port_security_enabled = true
|
||||||
shared = false
|
shared = false
|
||||||
region = var.main_region
|
region = var.main_region
|
||||||
}
|
}
|
||||||
|
|
||||||
# Subnet
|
# Subnet
|
||||||
resource "openstack_networking_subnet_v2" "timescaledb_subnet" {
|
resource "openstack_networking_subnet_v2" "timescaledb_subnet" {
|
||||||
name = "timescaledb-subnet"
|
name = "timescaledb-subnet"
|
||||||
description = "subnet used to connect to the shared TimeScaleDB service"
|
description = "subnet used to connect to the shared TimeScaleDB service"
|
||||||
network_id = openstack_networking_network_v2.timescaledb_net.id
|
network_id = openstack_networking_network_v2.timescaledb_net.id
|
||||||
cidr = var.timescaledb_net.network_cidr
|
cidr = var.timescaledb_net.network_cidr
|
||||||
dns_nameservers = var.resolvers_ip
|
dns_nameservers = var.resolvers_ip
|
||||||
ip_version = 4
|
ip_version = 4
|
||||||
enable_dhcp = true
|
enable_dhcp = true
|
||||||
no_gateway = true
|
no_gateway = true
|
||||||
allocation_pool {
|
allocation_pool {
|
||||||
start = var.timescaledb_net.allocation_pool_start
|
start = var.timescaledb_net.allocation_pool_start
|
||||||
end = var.timescaledb_net.allocation_pool_end
|
end = var.timescaledb_net.allocation_pool_end
|
||||||
|
@ -30,20 +30,20 @@ resource "openstack_networking_subnet_v2" "timescaledb_subnet" {
|
||||||
|
|
||||||
# Security group
|
# Security group
|
||||||
resource "openstack_networking_secgroup_v2" "timescaledb_access" {
|
resource "openstack_networking_secgroup_v2" "timescaledb_access" {
|
||||||
name = "access_to_the_timescaledb_service"
|
name = "access_to_the_timescaledb_service"
|
||||||
delete_default_rules = "true"
|
delete_default_rules = "true"
|
||||||
description = "Access the shared TimeScaleDB service using the dedicated network"
|
description = "Access the shared TimeScaleDB service using the dedicated network"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "openstack_networking_secgroup_rule_v2" "timescaledb_access_from_dedicated_subnet" {
|
resource "openstack_networking_secgroup_rule_v2" "timescaledb_access_from_dedicated_subnet" {
|
||||||
security_group_id = openstack_networking_secgroup_v2.timescaledb_access.id
|
security_group_id = openstack_networking_secgroup_v2.timescaledb_access.id
|
||||||
description = "Allow connections to port 5432 from the 192.168.11.0/24 network"
|
description = "Allow connections to port 5432 from the 192.168.11.0/24 network"
|
||||||
direction = "ingress"
|
direction = "ingress"
|
||||||
ethertype = "IPv4"
|
ethertype = "IPv4"
|
||||||
protocol = "tcp"
|
protocol = "tcp"
|
||||||
port_range_min = 5432
|
port_range_min = 5432
|
||||||
port_range_max = 5432
|
port_range_max = 5432
|
||||||
remote_ip_prefix = var.timescaledb_net.network_cidr
|
remote_ip_prefix = var.timescaledb_net.network_cidr
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "openstack_compute_servergroup_v2" "timescaledb_cluster" {
|
resource "openstack_compute_servergroup_v2" "timescaledb_cluster" {
|
||||||
|
@ -53,12 +53,12 @@ resource "openstack_compute_servergroup_v2" "timescaledb_cluster" {
|
||||||
|
|
||||||
# Instances with an additional block device
|
# Instances with an additional block device
|
||||||
resource "openstack_compute_instance_v2" "timescaledb_server" {
|
resource "openstack_compute_instance_v2" "timescaledb_server" {
|
||||||
count = var.timescaledb_nodes_count
|
count = var.timescaledb_nodes_count
|
||||||
name = var.timescaledb_server_data.node_name
|
name = var.timescaledb_server_data.node_name
|
||||||
availability_zone_hints = var.availability_zones_names.availability_zone_no_gpu
|
availability_zone_hints = var.availability_zones_names.availability_zone_no_gpu
|
||||||
flavor_name = var.timescaledb_node_flavor
|
flavor_name = var.timescaledb_node_flavor
|
||||||
key_pair = var.ssh_key_file.name
|
key_pair = var.ssh_key_file.name
|
||||||
security_groups = [var.default_security_group_name,openstack_networking_secgroup_v2.timescaledb_access.name]
|
security_groups = [var.default_security_group_name, openstack_networking_secgroup_v2.timescaledb_access.name]
|
||||||
scheduler_hints {
|
scheduler_hints {
|
||||||
group = openstack_compute_servergroup_v2.timescaledb_cluster.id
|
group = openstack_compute_servergroup_v2.timescaledb_cluster.id
|
||||||
}
|
}
|
||||||
|
@ -83,11 +83,11 @@ resource "openstack_compute_instance_v2" "timescaledb_server" {
|
||||||
name = var.main_private_network.name
|
name = var.main_private_network.name
|
||||||
}
|
}
|
||||||
network {
|
network {
|
||||||
name = var.timescaledb_net.network_name
|
name = var.timescaledb_net.network_name
|
||||||
fixed_ip_v4 = var.timescaledb_ip.*[count.index]
|
fixed_ip_v4 = var.timescaledb_ip.* [count.index]
|
||||||
}
|
}
|
||||||
|
|
||||||
user_data = "${file("${var.ubuntu2204_data_file}")}"
|
user_data = file("${var.ubuntu2204_data_file}")
|
||||||
depends_on = [openstack_networking_subnet_v2.timescaledb_subnet]
|
depends_on = [openstack_networking_subnet_v2.timescaledb_subnet]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue