diff --git a/Deployment/src/Modules/APIM/Modules/ExchangeSetService/main.tf b/Deployment/src/Modules/APIM/Modules/ExchangeSetService/main.tf index 8d3e282aa..12a6e328c 100644 --- a/Deployment/src/Modules/APIM/Modules/ExchangeSetService/main.tf +++ b/Deployment/src/Modules/APIM/Modules/ExchangeSetService/main.tf @@ -226,12 +226,42 @@ resource "azurerm_api_management_product_api" "ess_ui_product_api_mapping" { product_id = azurerm_api_management_product.ess_ui_product.product_id } +resource "azurerm_api_management_api" "ess_ui_api" { + resource_group_name = data.azurerm_resource_group.rg.name + api_management_name = data.azurerm_api_management.apim_instance.name + name = lower(replace(var.apim_ui_api_name, " ", "-")) + display_name = var.apim_ui_api_name + description = var.apim_ui_api_description + revision = "1" + path = var.apim_ui_api_path + protocols = ["https"] + service_url = var.apim_api_backend_url + + subscription_key_parameter_names { + header = "Ocp-Apim-Subscription-Key" + query = "subscription-key" + } + + import { + content_format = "openapi" + content_value = var.apim_ui_openapi + } +} + +# Add ESS UI API to ESS Product +resource "azurerm_api_management_product_api" "ess_product_ui_api_mapping" { + resource_group_name = data.azurerm_resource_group.rg.name + api_management_name = data.azurerm_api_management.apim_instance.name + api_name = azurerm_api_management_api.ess_ui_api.name + product_id = azurerm_api_management_product.ess_ui_product.product_id +} + # ESS UI Product poliy resource "azurerm_api_management_product_policy" "ess_ui_product_policy" { resource_group_name = data.azurerm_resource_group.rg.name api_management_name = data.azurerm_api_management.apim_instance.name product_id = azurerm_api_management_product.ess_ui_product.product_id - depends_on = [azurerm_api_management_product.ess_ui_product, azurerm_api_management_product_api.ess_ui_product_api_mapping] + depends_on = [azurerm_api_management_product.ess_ui_product, azurerm_api_management_product_api.ess_ui_product_api_mapping, azurerm_api_management_product_api.ess_product_ui_api_mapping] xml_content = < diff --git a/Deployment/src/Modules/APIM/Modules/ExchangeSetService/variables.tf b/Deployment/src/Modules/APIM/Modules/ExchangeSetService/variables.tf index f4d12f7ef..54d2b9c96 100644 --- a/Deployment/src/Modules/APIM/Modules/ExchangeSetService/variables.tf +++ b/Deployment/src/Modules/APIM/Modules/ExchangeSetService/variables.tf @@ -14,6 +14,10 @@ variable "apim_api_path" { type = string } +variable "apim_ui_api_path" { + type = string +} + variable "apim_api_backend_url" { type = string description = "The URL of the backend service serving the API." @@ -51,10 +55,22 @@ variable "apim_api_description" { type = string } +variable "apim_ui_api_name" { + type = string +} + +variable "apim_ui_api_description" { + type = string +} + variable "apim_api_openapi" { type = string } +variable "apim_ui_openapi" { + type = string +} + variable "client_credentials_operation_id" { type = string } diff --git a/Deployment/src/Modules/APIM/azure.tf b/Deployment/src/Modules/APIM/azure.tf index 47b273f04..437f90782 100644 --- a/Deployment/src/Modules/APIM/azure.tf +++ b/Deployment/src/Modules/APIM/azure.tf @@ -9,7 +9,6 @@ terraform { required_version = "=1.7.2" backend "azurerm" { container_name = "tfstate" - key = "terraform.ess.apim.deployment.tfplan" } } diff --git a/Deployment/src/Modules/APIM/main.tf b/Deployment/src/Modules/APIM/main.tf index 50aae6f13..065f572dc 100644 --- a/Deployment/src/Modules/APIM/main.tf +++ b/Deployment/src/Modules/APIM/main.tf @@ -3,15 +3,19 @@ module "exchange_set_service" { apim_name = var.apim_name apim_rg = var.apim_rg env_name = local.env_name - apim_api_path = local.apim_api_path + apim_api_path = local.apim_api_path + apim_ui_api_path = local.apim_ui_api_path apim_api_backend_url = var.apim_api_backend_url apim_group_name = local.group_name apim_group_description = var.group_description apim_ess_product_name = local.product_name apim_ess_product_description = var.product_description apim_api_name = local.api_name + apim_ui_api_name = local.ui_api_name apim_api_description = var.api_description + apim_ui_api_description = var.ui_api_description apim_api_openapi = local.apim_api_openapi + apim_ui_openapi = local.apim_ui_openapi product_rate_limit = var.product_rate_limit product_quota = var.product_quota client_credentials_operation_id = var.client_credentials_operation_id diff --git a/Deployment/src/Modules/APIM/variables.tf b/Deployment/src/Modules/APIM/variables.tf index 986038cb9..17446fd10 100644 --- a/Deployment/src/Modules/APIM/variables.tf +++ b/Deployment/src/Modules/APIM/variables.tf @@ -40,6 +40,16 @@ variable "api_description" { default = "The Exchange Set Service APIs to request ENC Exchange Sets for loading onto an ECDIS." } +variable "ui_api_name" { + type = string + default = "Exchange Set Service UI API" +} + +variable "ui_api_description" { + type = string + default = "The Exchange Set Service UI api to facilitate ESS UI Application Requests." +} + variable "ui_product_name" { type = string default = "Exchange Set Service UI" @@ -111,14 +121,25 @@ variable "cors_origin_values" { type = string } +variable "suffix" { + default = "" +} + +variable "pathsuffix" { + default = "" +} + locals { env_name = lower(terraform.workspace) service_name = "ess" - group_name = local.env_name == "prod" ? var.group_name : "${var.group_name} ${var.env_suffix[local.env_name]}" - product_name = local.env_name == "prod" ? var.product_name : "${var.product_name} ${var.env_suffix[local.env_name]}" - ui_product_name = local.env_name == "prod" ? var.ui_product_name : "${var.ui_product_name} ${var.env_suffix[local.env_name]}" - api_name = local.env_name == "prod" ? var.api_name : "${var.api_name} ${var.env_suffix[local.env_name]}" - apim_api_path = local.env_name == "prod" ? local.service_name : "${local.service_name}-${local.env_name}" + group_name = local.env_name == "prod" ? "${var.group_name}${var.suffix}" : "${var.group_name} ${var.env_suffix[local.env_name]}${var.suffix}" + product_name = local.env_name == "prod" ? "${var.product_name}${var.suffix}" : "${var.product_name} ${var.env_suffix[local.env_name]}${var.suffix}" + ui_product_name = local.env_name == "prod" ? "${var.ui_product_name}${var.suffix}" : "${var.ui_product_name} ${var.env_suffix[local.env_name]}${var.suffix}" + api_name = local.env_name == "prod" ? "${var.api_name}${var.suffix}" : "${var.api_name} ${var.env_suffix[local.env_name]}${var.suffix}" + ui_api_name = local.env_name == "prod" ? "${var.ui_api_name}${var.suffix}" : "${var.ui_api_name} ${var.env_suffix[local.env_name]}${var.suffix}" + apim_api_path = local.env_name == "prod" ? "${local.service_name}${var.pathsuffix}" : "${local.service_name}-${local.env_name}${var.pathsuffix}" + apim_ui_api_path = local.env_name == "prod" ? "${local.service_name}-ui-${var.pathsuffix}" : "${local.service_name}-ui-${local.env_name}${var.pathsuffix}" apim_api_openapi = file("${path.module}/exchangeSetService_OpenApi_definition.yaml") + apim_ui_openapi = file("${path.module}/exchangeSetService_Ui_OpenApi_definition.yaml") cors_origins = split(";", var.cors_origin_values) } \ No newline at end of file diff --git a/Deployment/src/Modules/CacheStorage/main.tf b/Deployment/src/Modules/CacheStorage/main.tf index a50515b7c..82e3f4e0c 100644 --- a/Deployment/src/Modules/CacheStorage/main.tf +++ b/Deployment/src/Modules/CacheStorage/main.tf @@ -1,5 +1,5 @@ resource "azurerm_storage_account" "ess_cache_storage" { - name = lower("${var.service_name}${var.env_name}cachestorageukho") + name = lower("${var.name}") resource_group_name = var.resource_group_name location = var.location account_tier = "Standard" diff --git a/Deployment/src/Modules/CacheStorage/variables.tf b/Deployment/src/Modules/CacheStorage/variables.tf index cc57374ce..a1ffbe7b6 100644 --- a/Deployment/src/Modules/CacheStorage/variables.tf +++ b/Deployment/src/Modules/CacheStorage/variables.tf @@ -6,10 +6,6 @@ variable "location" { type = string } -variable "env_name" { - type = string -} - variable "tags" { } @@ -36,4 +32,7 @@ variable "medium_exchange_set_subnets" { } variable "large_exchange_set_subnets" { -} \ No newline at end of file +} + +variable name { +} \ No newline at end of file diff --git a/Deployment/src/Modules/EventHub/main.tf b/Deployment/src/Modules/EventHub/main.tf index 24cdb5278..79d4448b7 100644 --- a/Deployment/src/Modules/EventHub/main.tf +++ b/Deployment/src/Modules/EventHub/main.tf @@ -16,21 +16,21 @@ resource "azurerm_eventhub" "eventhub" { } resource "azurerm_eventhub_consumer_group" "logstash_consumer_group" { - name = "logstash" + name = "logstash${var.suffix}" namespace_name = azurerm_eventhub_namespace.eventhub_namespace.name eventhub_name = azurerm_eventhub.eventhub.name resource_group_name = var.resource_group_name } resource "azurerm_eventhub_consumer_group" "logging_application_consumer_group" { - name = "loggingApplication" + name = "loggingApplication${var.suffix}" namespace_name = azurerm_eventhub_namespace.eventhub_namespace.name eventhub_name = azurerm_eventhub.eventhub.name resource_group_name = var.resource_group_name } resource "azurerm_eventhub_authorization_rule" "logstash" { - name = "logstashAccessKey" + name = "logstashAccessKey${var.suffix}" namespace_name = azurerm_eventhub_namespace.eventhub_namespace.name eventhub_name = azurerm_eventhub.eventhub.name resource_group_name = var.resource_group_name @@ -40,7 +40,7 @@ resource "azurerm_eventhub_authorization_rule" "logstash" { } resource "azurerm_eventhub_authorization_rule" "log" { - name = "logAccessKey" + name = "logAccessKey${var.suffix}" namespace_name = azurerm_eventhub_namespace.eventhub_namespace.name eventhub_name = azurerm_eventhub.eventhub.name resource_group_name = var.resource_group_name diff --git a/Deployment/src/Modules/EventHub/variables.tf b/Deployment/src/Modules/EventHub/variables.tf index 7b088859a..aa1caea09 100644 --- a/Deployment/src/Modules/EventHub/variables.tf +++ b/Deployment/src/Modules/EventHub/variables.tf @@ -29,3 +29,7 @@ variable "allowed_ips" { variable "tags" { } + +variable "suffix" { + default = "" +} diff --git a/Deployment/src/Modules/FulfilmentKeyVault/main.tf b/Deployment/src/Modules/FulfilmentKeyVault/main.tf index 23e173b96..02c5bf3d7 100644 --- a/Deployment/src/Modules/FulfilmentKeyVault/main.tf +++ b/Deployment/src/Modules/FulfilmentKeyVault/main.tf @@ -1,7 +1,7 @@ data "azurerm_client_config" "current" {} resource "azurerm_key_vault" "small_exchange_set_kv" { - name = lower("${var.service_name}-ukho-${var.env_name}-sxs-kv") + name = lower("${var.service_name}-ukho-${var.env_name}-sxs-kv${var.suffix}") location = var.location resource_group_name = var.resource_group_name enabled_for_disk_encryption = true @@ -69,7 +69,7 @@ resource "azurerm_key_vault_secret" "small_exchange_set_passed_in_secrets" { #Medium exchange set resource "azurerm_key_vault" "medium_exchange_set_kv" { - name = lower("${var.service_name}-ukho-${var.env_name}-mxs-kv") + name = lower("${var.service_name}-ukho-${var.env_name}-mxs-kv${var.suffix}") location = var.location resource_group_name = var.resource_group_name enabled_for_disk_encryption = true @@ -136,7 +136,7 @@ resource "azurerm_key_vault_secret" "medium_exchange_set_passed_in_secrets" { #Large exchange set resource "azurerm_key_vault" "large_exchange_set_kv" { - name = lower("${var.service_name}-ukho-${var.env_name}-lxs-kv") + name = lower("${var.service_name}-ukho-${var.env_name}-lxs-kv${var.suffix}") location = var.location resource_group_name = var.resource_group_name enabled_for_disk_encryption = true diff --git a/Deployment/src/Modules/FulfilmentKeyVault/variables.tf b/Deployment/src/Modules/FulfilmentKeyVault/variables.tf index 084cf3a27..fd576ac7e 100644 --- a/Deployment/src/Modules/FulfilmentKeyVault/variables.tf +++ b/Deployment/src/Modules/FulfilmentKeyVault/variables.tf @@ -53,4 +53,8 @@ variable "large_exchange_set_secrets" { variable "agent_subnet" { type = string +} + +variable "suffix" { + default = "" } \ No newline at end of file diff --git a/Deployment/src/Modules/FulfilmentStorage/main.tf b/Deployment/src/Modules/FulfilmentStorage/main.tf index 03d59fce2..8d19aa01f 100644 --- a/Deployment/src/Modules/FulfilmentStorage/main.tf +++ b/Deployment/src/Modules/FulfilmentStorage/main.tf @@ -1,5 +1,5 @@ resource "azurerm_storage_account" "small_exchange_set_storage" { - name = lower("${var.service_name}${var.env_name}sxsstorageukho") + name = lower("${var.service_name}${var.env_name}sxsstorageukho${var.suffix}") resource_group_name = var.resource_group_name location = var.location account_tier = "Standard" @@ -30,7 +30,7 @@ resource "azurerm_storage_queue" "small_exchange_set_storage_queue" { #Medium exchange set storage resource "azurerm_storage_account" "medium_exchange_set_storage" { - name = lower("${var.service_name}${var.env_name}mxsstorageukho") + name = lower("${var.service_name}${var.env_name}mxsstorageukho${var.suffix}") resource_group_name = var.resource_group_name location = var.location account_tier = "Standard" @@ -61,7 +61,7 @@ resource "azurerm_storage_queue" "medium_exchange_set_storage_queue" { #Large exchange set storage resource "azurerm_storage_account" "large_exchange_set_storage" { - name = lower("${var.service_name}${var.env_name}lxsstorageukho") + name = lower("${var.service_name}${var.env_name}lxsstorageukho${var.suffix}") resource_group_name = var.resource_group_name location = var.location account_tier = "Standard" diff --git a/Deployment/src/Modules/FulfilmentStorage/variables.tf b/Deployment/src/Modules/FulfilmentStorage/variables.tf index b14b46932..040ca78fb 100644 --- a/Deployment/src/Modules/FulfilmentStorage/variables.tf +++ b/Deployment/src/Modules/FulfilmentStorage/variables.tf @@ -41,4 +41,8 @@ variable "large_exchange_set_subnets" { variable "agent_subnet" { type = string +} + +variable "suffix" { + default = "" } \ No newline at end of file diff --git a/Deployment/src/Modules/FulfilmentWebapps/main.tf b/Deployment/src/Modules/FulfilmentWebapps/main.tf index 82d8b406a..4214accf5 100644 --- a/Deployment/src/Modules/FulfilmentWebapps/main.tf +++ b/Deployment/src/Modules/FulfilmentWebapps/main.tf @@ -1,6 +1,6 @@ resource "azurerm_app_service_plan" "small_exchange_set_app_service_plan" { count = var.exchange_set_config.SmallExchangeSetInstance - name = "${local.small_exchange_set_name}-${sum([1,count.index])}-asp" + name = "${local.small_exchange_set_name}-${sum([1,count.index])}-asp${var.suffix}" location = var.location resource_group_name = var.resource_group_name @@ -13,7 +13,7 @@ resource "azurerm_app_service_plan" "small_exchange_set_app_service_plan" { resource "azurerm_app_service" "small_exchange_set_webapp" { count = var.exchange_set_config.SmallExchangeSetInstance - name = "${local.small_exchange_set_name}-${sum([1,count.index])}-webapp" + name = "${local.small_exchange_set_name}-${sum([1,count.index])}-webapp${var.suffix}" location = var.location resource_group_name = var.resource_group_name app_service_plan_id = azurerm_app_service_plan.small_exchange_set_app_service_plan[count.index].id @@ -84,7 +84,7 @@ resource "azurerm_app_service_slot_virtual_network_swift_connection" "small_exch #Medium exchange set resource "azurerm_app_service_plan" "medium_exchange_set_app_service_plan" { count = var.exchange_set_config.MediumExchangeSetInstance - name = "${local.medium_exchange_set_name}-${sum([1,count.index])}-asp" + name = "${local.medium_exchange_set_name}-${sum([1,count.index])}-asp${var.suffix}" location = var.location resource_group_name = var.resource_group_name @@ -97,7 +97,7 @@ resource "azurerm_app_service_plan" "medium_exchange_set_app_service_plan" { resource "azurerm_app_service" "medium_exchange_set_webapp" { count = var.exchange_set_config.MediumExchangeSetInstance - name = "${local.medium_exchange_set_name}-${sum([1,count.index])}-webapp" + name = "${local.medium_exchange_set_name}-${sum([1,count.index])}-webapp${var.suffix}" location = var.location resource_group_name = var.resource_group_name app_service_plan_id = azurerm_app_service_plan.medium_exchange_set_app_service_plan[count.index].id @@ -168,7 +168,7 @@ resource "azurerm_app_service_slot_virtual_network_swift_connection" "medium_exc #Large exchange set resource "azurerm_app_service_plan" "large_exchange_set_app_service_plan" { count = var.exchange_set_config.LargeExchangeSetInstance - name = "${local.large_exchange_set_name}-${sum([1,count.index])}-asp" + name = "${local.large_exchange_set_name}-${sum([1,count.index])}-asp${var.suffix}" location = var.location resource_group_name = var.resource_group_name @@ -181,7 +181,7 @@ resource "azurerm_app_service_plan" "large_exchange_set_app_service_plan" { resource "azurerm_app_service" "large_exchange_set_webapp" { count = var.exchange_set_config.LargeExchangeSetInstance - name = "${local.large_exchange_set_name}-${sum([1,count.index])}-webapp" + name = "${local.large_exchange_set_name}-${sum([1,count.index])}-webapp${var.suffix}" location = var.location resource_group_name = var.resource_group_name app_service_plan_id = azurerm_app_service_plan.large_exchange_set_app_service_plan[count.index].id diff --git a/Deployment/src/Modules/FulfilmentWebapps/variables.tf b/Deployment/src/Modules/FulfilmentWebapps/variables.tf index f3e53be43..07a52b246 100644 --- a/Deployment/src/Modules/FulfilmentWebapps/variables.tf +++ b/Deployment/src/Modules/FulfilmentWebapps/variables.tf @@ -48,4 +48,8 @@ locals { small_exchange_set_name = "${var.service_name}-${var.env_name}-sxs" medium_exchange_set_name = "${var.service_name}-${var.env_name}-mxs" large_exchange_set_name = "${var.service_name}-${var.env_name}-lxs" +} + +variable "suffix" { + default = "" } \ No newline at end of file diff --git a/Deployment/src/Modules/UserIdentity/main.tf b/Deployment/src/Modules/UserIdentity/main.tf index 30df62416..b7a0ed359 100644 --- a/Deployment/src/Modules/UserIdentity/main.tf +++ b/Deployment/src/Modules/UserIdentity/main.tf @@ -1,6 +1,6 @@ resource "azurerm_user_assigned_identity" "ess_service_identity" { resource_group_name = var.resource_group_name location = var.location - name = "ess-${var.env_name}-service-identity" + name = "ess-${var.env_name}-service-identity${var.suffix}" tags = var.tags } \ No newline at end of file diff --git a/Deployment/src/Modules/UserIdentity/variables.tf b/Deployment/src/Modules/UserIdentity/variables.tf index 4fc3fe1db..2daa1bd92 100644 --- a/Deployment/src/Modules/UserIdentity/variables.tf +++ b/Deployment/src/Modules/UserIdentity/variables.tf @@ -12,4 +12,8 @@ variable "env_name" { variable "tags" { +} + +variable "suffix" { + default = "" } \ No newline at end of file diff --git a/Deployment/src/azure.tf b/Deployment/src/azure.tf index e8d886fb1..ce4ce883c 100644 --- a/Deployment/src/azure.tf +++ b/Deployment/src/azure.tf @@ -9,7 +9,6 @@ terraform { required_version = "=1.7.2" backend "azurerm" { container_name = "tfstate" - key = "terraform.deployment.tfplan" } } diff --git a/Deployment/src/main.tf b/Deployment/src/main.tf index 8f4b31f92..13b354065 100644 --- a/Deployment/src/main.tf +++ b/Deployment/src/main.tf @@ -36,13 +36,14 @@ module "user_identity" { source = "./Modules/UserIdentity" resource_group_name = azurerm_resource_group.rg.name location = azurerm_resource_group.rg.location + suffix = var.suffix env_name = local.env_name tags = local.tags } module "app_insights" { source = "./Modules/AppInsights" - name = "${local.service_name}-${local.env_name}-insights" + name = "${local.service_name}-${local.env_name}-insights${var.suffix}" resource_group_name = azurerm_resource_group.rg.name location = azurerm_resource_group.rg.location tags = local.tags @@ -50,10 +51,11 @@ module "app_insights" { module "eventhub" { source = "./Modules/EventHub" - name = "${local.service_name}-${local.env_name}-events" + name = "${local.service_name}-${local.env_name}-events${var.suffix}" resource_group_name = azurerm_resource_group.rg.name location = azurerm_resource_group.rg.location - logstashStorageName = lower("${local.service_name}logstash${local.env_name}") + logstashStorageName = lower("${local.service_name}logstash${local.env_name}${var.storage_suffix}") + suffix = var.suffix m_spoke_subnet = data.azurerm_subnet.main_subnet.id agent_subnet = data.azurerm_subnet.agent_subnet.id allowed_ips = var.allowed_ips @@ -89,6 +91,7 @@ module "fulfilment_webapp" { small_exchange_set_subnets = data.azurerm_subnet.small_exchange_set_subnet[*].id medium_exchange_set_subnets = data.azurerm_subnet.medium_exchange_set_subnet[*].id large_exchange_set_subnets = data.azurerm_subnet.large_exchange_set_subnet[*].id + suffix = var.suffix exchange_set_config = local.config_data.ESSFulfilmentConfiguration env_name = local.env_name service_name = local.service_name @@ -119,6 +122,7 @@ module "fulfilment_storage" { small_exchange_set_subnets = data.azurerm_subnet.small_exchange_set_subnet[*].id medium_exchange_set_subnets = data.azurerm_subnet.medium_exchange_set_subnet[*].id large_exchange_set_subnets = data.azurerm_subnet.large_exchange_set_subnet[*].id + suffix = var.storage_suffix m_spoke_subnet = data.azurerm_subnet.main_subnet.id agent_subnet = data.azurerm_subnet.agent_subnet.id exchange_set_config = local.config_data.ESSFulfilmentConfiguration @@ -166,6 +170,7 @@ module "fulfilment_keyvaults" { service_name = local.service_name resource_group_name = azurerm_resource_group.rg.name env_name = local.env_name + suffix = var.suffix tenant_id = module.user_identity.ess_service_identity_tenant_id location = azurerm_resource_group.rg.location allowed_ips = var.allowed_ips @@ -209,7 +214,7 @@ module "fulfilment_keyvaults" { module "azure-dashboard" { source = "./Modules/azuredashboard" - name = "ESS-${local.env_name}-Monitoring-Dashboard" + name = "ESS-${local.env_name}-Monitoring-Dashboard${var.suffix}" location = azurerm_resource_group.rg.location environment = local.env_name resource_group = azurerm_resource_group.rg @@ -217,6 +222,7 @@ module "azure-dashboard" { } module "cache_storage" { source = "./Modules/CacheStorage" + name = local.env_name == "prod" && var.storage_suffix == "v2" ? "${local.service_name}${local.env_name}cachestorageukho2" : "${local.service_name}${local.env_name}cachestorageukho${var.storage_suffix}" resource_group_name = azurerm_resource_group.rg.name allowed_ips = var.allowed_ips location = var.location @@ -226,6 +232,5 @@ module "cache_storage" { large_exchange_set_subnets = data.azurerm_subnet.large_exchange_set_subnet[*].id m_spoke_subnet = data.azurerm_subnet.main_subnet.id agent_subnet = data.azurerm_subnet.agent_subnet.id - env_name = local.env_name service_name = local.service_name } \ No newline at end of file diff --git a/Deployment/src/resource-group.tf b/Deployment/src/resource-group.tf index 2a9f14afb..f054a0339 100644 --- a/Deployment/src/resource-group.tf +++ b/Deployment/src/resource-group.tf @@ -1,5 +1,5 @@ resource "azurerm_resource_group" "rg" { - name = "${var.resource_group_name}-${local.env_name}-rg" + name = "${var.resource_group_name}-${local.env_name}-rg${var.suffix}" location = var.location tags = local.tags } \ No newline at end of file diff --git a/Deployment/src/variables.tf b/Deployment/src/variables.tf index bf462f2b8..ca6bfb4d1 100644 --- a/Deployment/src/variables.tf +++ b/Deployment/src/variables.tf @@ -11,8 +11,8 @@ variable "resource_group_name" { locals { env_name = lower(terraform.workspace) service_name = "ess" -web_app_name = "${local.service_name}-${local.env_name}-webapp" - key_vault_name = "${local.service_name}-ukho-${local.env_name}-kv" + web_app_name = "${local.service_name}-${local.env_name}-webapp${var.suffix}" + key_vault_name = "${local.service_name}-ukho-${local.env_name}-kv${var.suffix}" tags = { SERVICE = "Exchange Set Service" ENVIRONMENT = local.env_name @@ -86,4 +86,12 @@ variable "elastic_apm_server_url" { } variable "elastic_apm_api_key" { +} + +variable "suffix" { + default = "" +} + +variable "storage_suffix" { + default = "" } \ No newline at end of file diff --git a/Deployment/templates/continuous-deployment-apim-v2.yml b/Deployment/templates/continuous-deployment-apim-v2.yml new file mode 100644 index 000000000..3ad54a8bf --- /dev/null +++ b/Deployment/templates/continuous-deployment-apim-v2.yml @@ -0,0 +1,49 @@ +parameters: + - name: ContinueEvenIfResourcesAreGettingDestroyed + type: boolean + default: false + - name: AzureSubscription + type: string + - name: TerraformKeyVault + type: string + - name: APIMResourceGroup + type: string + - name: APIMServiceInstance + type: string + - name: tfstateStorageAccountRG + type: string + - name: tfstateStorageAccountName + type: string + +steps: + - task: AzureKeyVault@1 + displayName: 'Read APIM terraform Variables' + inputs: + azureSubscription: "${{ parameters.AzureSubscription }}" + KeyVaultName: "${{ parameters.TerraformKeyVault }}" + SecretsFilter: '*' + RunAsPreJob: false + + - task: PowerShell@2 + name: APIMDeployment + displayName: "terraform APIM deployment" + inputs: + targetType: filePath + filePath: '$(Pipeline.Workspace)/terraformartifact/terraform_conditional_run_apim_v2.ps1' + arguments: '-deploymentResourceGroupName ${{ parameters.tfstateStorageAccountRG }} -deploymentStorageAccountName ${{ parameters.tfstateStorageAccountName }} -workSpace $(Environment) -continueEvenIfResourcesAreGettingDestroyed $${{ parameters.ContinueEvenIfResourcesAreGettingDestroyed }}' + env: + ARM_CLIENT_ID: $(TERRAFORM-CLIENT-ID) + ARM_CLIENT_SECRET: $(TERRAFORM-CLIENT-SECRET) + ARM_TENANT_ID: $(TERRAFORM-TENANT-ID) + ARM_SUBSCRIPTION_ID: $(TERRAFORM-SUBSCRIPTION-ID) + TF_VAR_apim_rg: ${{ parameters.APIMResourceGroup }} + TF_VAR_apim_name: ${{ parameters.APIMServiceInstance }} + TF_VAR_apim_api_backend_url: $(EssApiUrl) + TF_VAR_client_credentials_tenant_id: $(AzureAdB2CConfiguration.TenantId) + TF_VAR_client_credentials_scope: "$(AzureAdB2CConfiguration.ClientId)/.default" + TF_VAR_b2c_token_issuer: "$(APIM_B2C_TOKEN_ISSUER)" + TF_VAR_b2c_client_id: "$(APIM_B2C_CLIENT_ID)" + TF_VAR_cors_origin_values: "$(APIM_CORS_ORIGIN_VALUES)" + TF_VAR_ess_ui_product_call_limit: $(essuiproductcalllimit) + TF_VAR_ess_ui_product_call_renewal_period: $(essuiproductcallrenewalperiod) + TF_VAR_ess_ui_product_daily_quota_limit: $(essuiproductdailyquotalimit) \ No newline at end of file diff --git a/Deployment/templates/continuous-deployment-v2.yml b/Deployment/templates/continuous-deployment-v2.yml new file mode 100644 index 000000000..89e6e08da --- /dev/null +++ b/Deployment/templates/continuous-deployment-v2.yml @@ -0,0 +1,104 @@ +parameters: + - name: ContinueEvenIfResourcesAreGettingDestroyed + type: boolean + default: false + - name: AzureSubscription + type: string + +steps: + - task: FileTransform@2 + displayName: "File Transform: Ess Config" #Replace exchange set instance value from pipeline + inputs: + folderPath: '$(Pipeline.Workspace)/terraformartifact/src' + xmlTransformationRules: + jsonTargetFiles: '**/appsettings.json' + + - task: PowerShell@2 + displayName: "terraform devdeploy for FSSUI" + inputs: + targetType: filePath + filePath: '$(Pipeline.Workspace)/terraformartifact/terraform_conditional_run_v2.ps1' + arguments: '-deploymentResourceGroupName $(DeploymentResourceGroupName) -deploymentStorageAccountName $(DeploymentStorageAccountName) -workSpace $(Environment) -continueEvenIfResourcesAreGettingDestroyed $${{ parameters.ContinueEvenIfResourcesAreGettingDestroyed }} -terraformJsonOutputFile $(Pipeline.Workspace)/terraformartifact/terraform_output.json -elasticApmServerUrl $(ElasticAPM.ServerURL) -elasticApmApiKey $(ElasticAPM.ApiKey)' + env: + ARM_CLIENT_ID: $(TERRAFORM-CLIENT-ID) + ARM_CLIENT_SECRET: $(TERRAFORM-CLIENT-SECRET) + ARM_TENANT_ID: $(TERRAFORM-TENANT-ID) + ARM_SUBSCRIPTION_ID: $(TERRAFORM-SUBSCRIPTION-ID) + TF_VAR_allowed_ips: $(whiteListedIps) + TF_VAR_spoke_rg: $(spokeRG) + TF_VAR_spoke_vnet_name: $(spokeVnetName) + TF_VAR_spoke_subnet_name: $(spokeSubnetName) + TF_VAR_agent_rg: $(agentRG) + TF_VAR_agent_vnet_name: $(agentVnetName) + TF_VAR_agent_subnet_name: $(agentSubnetName) + TF_VAR_agent_subscription_id: $(agentSubscriptionId) + + - task: FileTransform@2 + displayName: "File Transform: WebJob" + inputs: + folderPath: '$(Pipeline.Workspace)/ExchangeSetService/*.zip' + xmlTransformationRules: + jsonTargetFiles: '**/appsettings.json' + + - task: AzureCLI@2 + displayName: "Azure Fulfilment Webjob Deployment" + inputs: + azureSubscription: "${{ parameters.AzureSubscription }}" + scriptType: 'pscore' + scriptLocation: 'scriptPath' + scriptPath: '$(Pipeline.Workspace)/terraformartifact/fulfilment_webjob_deployment.ps1' + arguments: '-terraformJsonOutputFile $(Pipeline.Workspace)/terraformartifact/terraform_output.json -packagePath "$(Pipeline.Workspace)/ExchangeSetService" -packageName "ExchangeSetFulFilmentService.zip"' + + + - task: FileTransform@2 + displayName: "File Transform: WebAppSettings" + inputs: + folderPath: '$(Pipeline.Workspace)/ExchangeSetServiceWebAPI/*.zip' + xmlTransformationRules: + jsonTargetFiles: '**/appsettings.json' + + - task: AzureWebApp@1 + displayName: "Azure App Deploy: ess-$(Environment)-webapp to Staging slot" + inputs: + azureSubscription: "${{ parameters.AzureSubscription }}" + appType: webApp + appName: "$(WEB_APP_NAME)" + package: "$(Pipeline.Workspace)/ExchangeSetServiceWebAPI/UKHO.ExchangeSetService.API.zip" + deployToSlotOrASE: true + slotName: $(WEB_APP_SLOT_NAME) + + - task: AzureAppServiceManage@0 + displayName: "Swap with production slot" + inputs: + azureSubscription: "${{ parameters.AzureSubscription }}" + resourceGroupName: $(RESOURCE_GROUP_NAME) + webAppName: $(WEB_APP_NAME) + action: "Swap Slots" + swapWithProduction: true + sourceSlot: $(WEB_APP_SLOT_NAME) + + # - task: PowerShell@2 + # displayName: "Check the status of production slot" + # inputs: + # targetType: filePath + # filePath: "$(Pipeline.Workspace)/terraformartifact/check_service_status.ps1" + # arguments: "-healthEndPointUrl $(EssApiUrl)/health -waitTimeInMinute $(waitTimeInMinute) -onErrorContinue 1" + + - task: AzureAppServiceManage@0 + displayName: "Swap with production slot - Rollback" + condition: and(succeeded(), eq(variables['IS_HEALTHY'], 'false')) + inputs: + azureSubscription: "${{ parameters.AzureSubscription }}" + resourceGroupName: $(RESOURCE_GROUP_NAME) + webAppName: $(WEB_APP_NAME) + action: "Swap Slots" + swapWithProduction: true + sourceSlot: $(WEB_APP_SLOT_NAME) + + # - task: PowerShell@2 + # displayName: "Check the status of production slot after rollback" + # condition: and(succeeded(), eq(variables['IS_HEALTHY'], 'false')) + # inputs: + # targetType: filePath + # filePath: "$(Pipeline.Workspace)/terraformartifact/check_service_status.ps1" + # arguments: "-healthEndPointUrl $(EssApiUrl)/health -waitTimeInMinute $(waitTimeInMinute) -onErrorContinue 0" diff --git a/Deployment/templates/continuous-deployment.yml b/Deployment/templates/continuous-deployment.yml index 5b98816ef..572e7fea4 100644 --- a/Deployment/templates/continuous-deployment.yml +++ b/Deployment/templates/continuous-deployment.yml @@ -33,72 +33,72 @@ steps: TF_VAR_agent_subnet_name: $(agentSubnetName) TF_VAR_agent_subscription_id: $(agentSubscriptionId) - - task: FileTransform@2 - displayName: "File Transform: WebJob" - inputs: - folderPath: '$(Pipeline.Workspace)/ExchangeSetService/*.zip' - xmlTransformationRules: - jsonTargetFiles: '**/appsettings.json' + # - task: FileTransform@2 + # displayName: "File Transform: WebJob" + # inputs: + # folderPath: '$(Pipeline.Workspace)/ExchangeSetService/*.zip' + # xmlTransformationRules: + # jsonTargetFiles: '**/appsettings.json' - - task: AzureCLI@2 - displayName: "Azure Fulfilment Webjob Deployment" - inputs: - azureSubscription: "${{ parameters.AzureSubscription }}" - scriptType: 'pscore' - scriptLocation: 'scriptPath' - scriptPath: '$(Pipeline.Workspace)/terraformartifact/fulfilment_webjob_deployment.ps1' - arguments: '-terraformJsonOutputFile $(Pipeline.Workspace)/terraformartifact/terraform_output.json -packagePath "$(Pipeline.Workspace)/ExchangeSetService" -packageName "ExchangeSetFulFilmentService.zip"' + # - task: AzureCLI@2 + # displayName: "Azure Fulfilment Webjob Deployment" + # inputs: + # azureSubscription: "${{ parameters.AzureSubscription }}" + # scriptType: 'pscore' + # scriptLocation: 'scriptPath' + # scriptPath: '$(Pipeline.Workspace)/terraformartifact/fulfilment_webjob_deployment.ps1' + # arguments: '-terraformJsonOutputFile $(Pipeline.Workspace)/terraformartifact/terraform_output.json -packagePath "$(Pipeline.Workspace)/ExchangeSetService" -packageName "ExchangeSetFulFilmentService.zip"' - - task: FileTransform@2 - displayName: "File Transform: WebAppSettings" - inputs: - folderPath: '$(Pipeline.Workspace)/ExchangeSetServiceWebAPI/*.zip' - xmlTransformationRules: - jsonTargetFiles: '**/appsettings.json' + # - task: FileTransform@2 + # displayName: "File Transform: WebAppSettings" + # inputs: + # folderPath: '$(Pipeline.Workspace)/ExchangeSetServiceWebAPI/*.zip' + # xmlTransformationRules: + # jsonTargetFiles: '**/appsettings.json' - - task: AzureWebApp@1 - displayName: "Azure App Deploy: ess-$(Environment)-webapp to Staging slot" - inputs: - azureSubscription: "${{ parameters.AzureSubscription }}" - appType: webApp - appName: "$(WEB_APP_NAME)" - package: "$(Pipeline.Workspace)/ExchangeSetServiceWebAPI/UKHO.ExchangeSetService.API.zip" - deployToSlotOrASE: true - slotName: $(WEB_APP_SLOT_NAME) + # - task: AzureWebApp@1 + # displayName: "Azure App Deploy: ess-$(Environment)-webapp to Staging slot" + # inputs: + # azureSubscription: "${{ parameters.AzureSubscription }}" + # appType: webApp + # appName: "$(WEB_APP_NAME)" + # package: "$(Pipeline.Workspace)/ExchangeSetServiceWebAPI/UKHO.ExchangeSetService.API.zip" + # deployToSlotOrASE: true + # slotName: $(WEB_APP_SLOT_NAME) - - task: AzureAppServiceManage@0 - displayName: "Swap with production slot" - inputs: - azureSubscription: "${{ parameters.AzureSubscription }}" - resourceGroupName: $(RESOURCE_GROUP_NAME) - webAppName: $(WEB_APP_NAME) - action: "Swap Slots" - swapWithProduction: true - sourceSlot: $(WEB_APP_SLOT_NAME) + # - task: AzureAppServiceManage@0 + # displayName: "Swap with production slot" + # inputs: + # azureSubscription: "${{ parameters.AzureSubscription }}" + # resourceGroupName: $(RESOURCE_GROUP_NAME) + # webAppName: $(WEB_APP_NAME) + # action: "Swap Slots" + # swapWithProduction: true + # sourceSlot: $(WEB_APP_SLOT_NAME) - - task: PowerShell@2 - displayName: "Check the status of production slot" - inputs: - targetType: filePath - filePath: "$(Pipeline.Workspace)/terraformartifact/check_service_status.ps1" - arguments: "-healthEndPointUrl $(EssApiUrl)/health -waitTimeInMinute $(waitTimeInMinute) -onErrorContinue 1" + # - task: PowerShell@2 + # displayName: "Check the status of production slot" + # inputs: + # targetType: filePath + # filePath: "$(Pipeline.Workspace)/terraformartifact/check_service_status.ps1" + # arguments: "-healthEndPointUrl $(EssApiUrl)/health -waitTimeInMinute $(waitTimeInMinute) -onErrorContinue 1" - - task: AzureAppServiceManage@0 - displayName: "Swap with production slot - Rollback" - condition: and(succeeded(), eq(variables['IS_HEALTHY'], 'false')) - inputs: - azureSubscription: "${{ parameters.AzureSubscription }}" - resourceGroupName: $(RESOURCE_GROUP_NAME) - webAppName: $(WEB_APP_NAME) - action: "Swap Slots" - swapWithProduction: true - sourceSlot: $(WEB_APP_SLOT_NAME) + # - task: AzureAppServiceManage@0 + # displayName: "Swap with production slot - Rollback" + # condition: and(succeeded(), eq(variables['IS_HEALTHY'], 'false')) + # inputs: + # azureSubscription: "${{ parameters.AzureSubscription }}" + # resourceGroupName: $(RESOURCE_GROUP_NAME) + # webAppName: $(WEB_APP_NAME) + # action: "Swap Slots" + # swapWithProduction: true + # sourceSlot: $(WEB_APP_SLOT_NAME) - - task: PowerShell@2 - displayName: "Check the status of production slot after rollback" - condition: and(succeeded(), eq(variables['IS_HEALTHY'], 'false')) - inputs: - targetType: filePath - filePath: "$(Pipeline.Workspace)/terraformartifact/check_service_status.ps1" - arguments: "-healthEndPointUrl $(EssApiUrl)/health -waitTimeInMinute $(waitTimeInMinute) -onErrorContinue 0" + # - task: PowerShell@2 + # displayName: "Check the status of production slot after rollback" + # condition: and(succeeded(), eq(variables['IS_HEALTHY'], 'false')) + # inputs: + # targetType: filePath + # filePath: "$(Pipeline.Workspace)/terraformartifact/check_service_status.ps1" + # arguments: "-healthEndPointUrl $(EssApiUrl)/health -waitTimeInMinute $(waitTimeInMinute) -onErrorContinue 0" diff --git a/Deployment/terraform_conditional_run.ps1 b/Deployment/terraform_conditional_run.ps1 index 72175a7ee..00e1d9bc7 100644 --- a/Deployment/terraform_conditional_run.ps1 +++ b/Deployment/terraform_conditional_run.ps1 @@ -28,7 +28,7 @@ terraform validate if ( !$? ) { echo "Something went wrong during terraform validation" ; throw "Error" } Write-output "Execute Terraform plan" -terraform plan -out "terraform.deployment.tfplan" -var elastic_apm_server_url=$elasticApmServerUrl -var elastic_apm_api_key=$elasticApmApiKey | tee terraform_output.txt +terraform plan -out "terraform.deployment.tfplan" -var elastic_apm_server_url=$elasticApmServerUrl -var elastic_apm_api_key=$elasticApmApiKey -var suffix="" -var storage_suffix="" | tee terraform_output.txt if ( !$? ) { echo "Something went wrong during terraform plan" ; throw "Error" } $totalDestroyLines=(Get-Content -Path terraform_output.txt | Select-String -Pattern "destroy" -CaseSensitive | where {$_ -ne ""}).length @@ -45,7 +45,7 @@ if($totalDestroyLines -ge 2) } Write-output "Executing terraform apply" -terraform apply "terraform.deployment.tfplan" +#terraform apply "terraform.deployment.tfplan" if ( !$? ) { echo "Something went wrong during terraform apply" ; throw "Error" } Write-output "Terraform output as json" diff --git a/Deployment/terraform_conditional_run_apim.ps1 b/Deployment/terraform_conditional_run_apim.ps1 index 4a11692bc..dab68f9ab 100644 --- a/Deployment/terraform_conditional_run_apim.ps1 +++ b/Deployment/terraform_conditional_run_apim.ps1 @@ -26,7 +26,7 @@ terraform validate if ( !$? ) { echo "Something went wrong during terraform validation" ; throw "Error" } Write-output "Execute Terraform plan..." -terraform plan -out "terraform.ess.apim.deployment.tfplan" | tee terraform_output.txt +terraform plan -out "terraform.ess.apim.deployment.tfplan" -var suffix="" -var pathsuffix="" | tee terraform_output.txt if ( !$? ) { echo "Something went wrong during terraform plan" ; throw "Error" } $totalDestroyLines=(Get-Content -Path terraform_output.txt | Select-String -Pattern "destroy" -CaseSensitive | where {$_ -ne ""}).length @@ -43,5 +43,5 @@ if($totalDestroyLines -ge 2) } Write-output "Executing terraform apply..." -terraform apply "terraform.ess.apim.deployment.tfplan" +#terraform apply "terraform.ess.apim.deployment.tfplan" if ( !$? ) { echo "Something went wrong during terraform apply" ; throw "Error" } \ No newline at end of file diff --git a/Deployment/terraform_conditional_run_apim_v2.ps1 b/Deployment/terraform_conditional_run_apim_v2.ps1 new file mode 100644 index 000000000..d6d646ecc --- /dev/null +++ b/Deployment/terraform_conditional_run_apim_v2.ps1 @@ -0,0 +1,47 @@ +param ( + [Parameter(Mandatory = $true)] [string] $deploymentResourceGroupName, + [Parameter(Mandatory = $true)] [string] $deploymentStorageAccountName, + [Parameter(Mandatory = $true)] [string] $workSpace, + [Parameter(Mandatory = $true)] [boolean] $continueEvenIfResourcesAreGettingDestroyed +) + +cd $env:AGENT_BUILDDIRECTORY/terraformartifact/src/Modules/APIM/ + +Write-output "Executing terraform scripts for APIM deployment in $workSpace enviroment..." + +terraform init -backend-config="resource_group_name=$deploymentResourceGroupName" -backend-config="storage_account_name=$deploymentStorageAccountName" -backend-config="key=terraform.ess.apim.deployment.v2.tfplan" +if ( !$? ) { echo "Something went wrong during terraform initialization"; throw "Error" } + +Write-output "Selecting workspace..." + +$ErrorActionPreference = 'SilentlyContinue' +terraform workspace new $WorkSpace 2>&1 > $null +$ErrorActionPreference = 'Continue' + +terraform workspace select $workSpace +if ( !$? ) { echo "Error while selecting workspace"; throw "Error" } + +Write-output "Validating terraform..." +terraform validate +if ( !$? ) { echo "Something went wrong during terraform validation" ; throw "Error" } + +Write-output "Execute Terraform plan..." +terraform plan -out "terraform.ess.apim.deployment.v2.tfplan" -var suffix=" v2" -var pathsuffix="-v2" | tee terraform_output.txt +if ( !$? ) { echo "Something went wrong during terraform plan" ; throw "Error" } + +$totalDestroyLines=(Get-Content -Path terraform_output.txt | Select-String -Pattern "destroy" -CaseSensitive | where {$_ -ne ""}).length +if($totalDestroyLines -ge 2) +{ + write-Host("Terraform is destroying some resources, please verify...................") + if ( !$ContinueEvenIfResourcesAreGettingDestroyed) + { + write-Host("exiting...................") + Write-Output $_ + exit 1 + } + write-host("Continue executing terraform apply - as continueEvenIfResourcesAreGettingDestroyed param is set to true in pipeline...") +} + +Write-output "Executing terraform apply..." +terraform apply "terraform.ess.apim.deployment.v2.tfplan" +if ( !$? ) { echo "Something went wrong during terraform apply" ; throw "Error" } \ No newline at end of file diff --git a/Deployment/terraform_conditional_run_v2.ps1 b/Deployment/terraform_conditional_run_v2.ps1 new file mode 100644 index 000000000..14422b4d1 --- /dev/null +++ b/Deployment/terraform_conditional_run_v2.ps1 @@ -0,0 +1,65 @@ +param ( + [Parameter(Mandatory = $true)] [string] $deploymentResourceGroupName, + [Parameter(Mandatory = $true)] [string] $deploymentStorageAccountName, + [Parameter(Mandatory = $true)] [string] $workSpace, + [Parameter(Mandatory = $true)] [boolean] $continueEvenIfResourcesAreGettingDestroyed, + [Parameter(Mandatory = $true)] [string] $terraformJsonOutputFile, + [Parameter(Mandatory = $true)] [string] $elasticApmServerUrl, + [Parameter(Mandatory = $true)] [string] $elasticApmApiKey +) + +cd $env:AGENT_BUILDDIRECTORY/terraformartifact/src + +Write-output "Executing terraform scripts for deployment in $workSpace enviroment" +terraform init -backend-config="resource_group_name=$deploymentResourceGroupName" -backend-config="storage_account_name=$deploymentStorageAccountName" -backend-config="key=terraform.deployment.v2.tfplan" +if ( !$? ) { echo "Something went wrong during terraform initialization"; throw "Error" } + +Write-output "Selecting workspace" + +$ErrorActionPreference = 'SilentlyContinue' +terraform workspace new $WorkSpace 2>&1 > $null +$ErrorActionPreference = 'Continue' + +terraform workspace select $workSpace +if ( !$? ) { echo "Error while selecting workspace"; throw "Error" } + +Write-output "Validating terraform" +terraform validate +if ( !$? ) { echo "Something went wrong during terraform validation" ; throw "Error" } + +Write-output "Execute Terraform plan" +terraform plan -out "terraform.deployment.v2.tfplan" -var elastic_apm_server_url=$elasticApmServerUrl -var elastic_apm_api_key=$elasticApmApiKey -var suffix="-v2" -var storage_suffix="v2" | tee terraform_output.txt +if ( !$? ) { echo "Something went wrong during terraform plan" ; throw "Error" } + +$totalDestroyLines=(Get-Content -Path terraform_output.txt | Select-String -Pattern "destroy" -CaseSensitive | where {$_ -ne ""}).length +if($totalDestroyLines -ge 2) +{ + write-Host("Terraform is destroying some resources, please verify...................") + if ( !$ContinueEvenIfResourcesAreGettingDestroyed) + { + write-Host("exiting...................") + Write-Output $_ + exit 1 + } + write-host("Continue executing terraform apply - as continueEvenIfResourcesAreGettingDestroyed param is set to true in pipeline") +} + +Write-output "Executing terraform apply" +terraform apply "terraform.deployment.v2.tfplan" +if ( !$? ) { echo "Something went wrong during terraform apply" ; throw "Error" } + +Write-output "Terraform output as json" +$terraformOutput = terraform output -json | ConvertFrom-Json + +write-output "Set JSON output into pipeline variables" +Write-Host "##vso[task.setvariable variable=WEB_APP_NAME]$($terraformOutput.web_app_name.value)" +Write-Host "##vso[task.setvariable variable=EssApiUrl]$env:SERVICE_DNS_URL" +Write-Host "##vso[task.setvariable variable=KeyVaultSettings.ServiceUri]$($terraformOutput.keyvault_uri.value)" +Write-Host "##vso[task.setvariable variable=EssStorageAccountConnectionString;issecret=true]$($terraformOutput.storage_connection_string.value)" +Write-Host "##vso[task.setvariable variable=ESSManagedIdentity.ClientId]$($terraformOutput.ess_managed_user_identity_client_id.value)" +Write-Host "##vso[task.setvariable variable=RESOURCE_GROUP_NAME]$($terraformOutput.web_app_resource_group.value)" +Write-Host "##vso[task.setvariable variable=WEB_APP_SLOT_NAME]$($terraformOutput.web_app_slot_name.value)" +Write-Host "##vso[task.setvariable variable=WEB_APP_SLOT_HOST_NAME]$($terraformOutput.web_app_slot_default_site_hostname.value)" + + +$terraformOutput | ConvertTo-Json -Depth 5 > $terraformJsonOutputFile \ No newline at end of file diff --git a/NVDSuppressions.xml b/NVDSuppressions.xml index 968fa2643..6f441278c 100644 --- a/NVDSuppressions.xml +++ b/NVDSuppressions.xml @@ -463,4 +463,14 @@ CVE-2024-21907 + + + + + CVE-2024-21386 + CVE-2024-21404 + diff --git a/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.API/appsettings.json b/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.API/appsettings.json index 09eeaf319..bfd5174d4 100644 --- a/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.API/appsettings.json +++ b/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.API/appsettings.json @@ -71,7 +71,8 @@ "LargeMediaExchangeSetSizeInMB": 700, "LargeExchangeSetSizeInMB": 300, "SmallExchangeSetSizeInMB": 50, - "ExchangeSetTypes": "sxs,mxs,lxs" + "ExchangeSetTypes": "sxs,mxs,lxs", + "WebAppVersion": "" }, "ESSManagedIdentity": { "ClientId": "", diff --git a/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.API/appsettings.local.overrides.json b/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.API/appsettings.local.overrides.json index 387a38740..cc9ebc9e9 100644 --- a/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.API/appsettings.local.overrides.json +++ b/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.API/appsettings.local.overrides.json @@ -32,7 +32,8 @@ "LargeMediaExchangeSetSizeInMB": 700, "LargeExchangeSetSizeInMB": 300, "SmallExchangeSetSizeInMB": 50, - "ExchangeSetTypes": "sxs,mxs,lxs" + "ExchangeSetTypes": "sxs,mxs,lxs", + "WebAppVersion": "dev" }, "CacheConfiguration": { "CacheStorageAccountName": "", diff --git a/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.Common.UnitTests/HealthCheck/AzureMessageQueueHealthCheckTest.cs b/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.Common.UnitTests/HealthCheck/AzureMessageQueueHealthCheckTest.cs index 5911f5547..9fe108cfa 100644 --- a/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.Common.UnitTests/HealthCheck/AzureMessageQueueHealthCheckTest.cs +++ b/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.Common.UnitTests/HealthCheck/AzureMessageQueueHealthCheckTest.cs @@ -31,7 +31,7 @@ public void Setup() this.fakeAzureBlobStorageService = A.Fake(); this.fakeEssFulfilmentStorageConfiguration = Options.Create(new EssFulfilmentStorageConfiguration() - { QueueName = "testessdevqueue", StorageAccountKey = "testaccountkey", StorageAccountName = "testessdevstorage", StorageContainerName = "testContainer", DynamicQueueName = "testDynamicQueue", ExchangeSetTypes= "test" }); + { QueueName = "testessdevqueue", StorageAccountKey = "testaccountkey", StorageAccountName = "testessdevstorage", StorageContainerName = "testContainer", DynamicQueueName = "testDynamicQueue", ExchangeSetTypes= "test", WebAppVersion = "" }); azureMessageQueueHealthCheck = new AzureMessageQueueHealthCheck(fakeAzureMessageQueueHelperClient, fakeSalesCatalogueStorageService, fakeEssFulfilmentStorageConfiguration, fakeLogger, fakeAzureBlobStorageService); } diff --git a/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.Common.UnitTests/HealthCheck/AzureWebJobsHealthCheckServiceTest.cs b/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.Common.UnitTests/HealthCheck/AzureWebJobsHealthCheckServiceTest.cs index 698610323..85eff0d96 100644 --- a/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.Common.UnitTests/HealthCheck/AzureWebJobsHealthCheckServiceTest.cs +++ b/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.Common.UnitTests/HealthCheck/AzureWebJobsHealthCheckServiceTest.cs @@ -24,7 +24,7 @@ public class AzureWebJobsHealthCheckServiceTest [SetUp] public void Setup() { - this.fakeEssFulfilmentStorageConfiguration = Options.Create(new EssFulfilmentStorageConfiguration() { ExchangeSetTypes = "sxs,mxs,lxs" }); + this.fakeEssFulfilmentStorageConfiguration = Options.Create(new EssFulfilmentStorageConfiguration() { ExchangeSetTypes = "sxs,mxs,lxs", WebAppVersion = ""}); this.fakeWebJobsAccessKeyProvider = A.Fake(); this.fakeWebHostEnvironment = A.Fake(); this.fakeAzureBlobStorageService = A.Fake(); @@ -56,5 +56,33 @@ public async Task WhenAzureWebJobStatusIsRunning_ThenReturnHealthy() Assert.AreEqual(HealthStatus.Healthy, response.Status); } + + [Test] + public async Task WhenAzureWebJobStatusIsNotRunningForV2_ThenReturnUnhealthy() + { + this.fakeEssFulfilmentStorageConfiguration.Value.WebAppVersion = "v2"; + + A.CallTo(() => fakeAzureBlobStorageService.GetInstanceCountBasedOnExchangeSetType(A.Ignored)).Returns(1); + A.CallTo(() => fakeAzureWebJobsHealthCheckClient.CheckAllWebJobsHealth(A>.Ignored)) + .Returns(new HealthCheckResult(HealthStatus.Unhealthy, "Azure message queue is unhealthy")); + + var response = await azureWebJobsHealthCheckService.CheckHealthAsync(); + + Assert.AreEqual(HealthStatus.Unhealthy, response.Status); + } + + [Test] + public async Task WhenAzureWebJobStatusIsRunningForV2_ThenReturnHealthy() + { + this.fakeEssFulfilmentStorageConfiguration.Value.WebAppVersion = "v2"; + + A.CallTo(() => fakeAzureBlobStorageService.GetInstanceCountBasedOnExchangeSetType(A.Ignored)).Returns(1); + A.CallTo(() => fakeAzureWebJobsHealthCheckClient.CheckAllWebJobsHealth(A>.Ignored)) + .Returns(new HealthCheckResult(HealthStatus.Healthy, "Azure message queue is healthy")); + + var response = await azureWebJobsHealthCheckService.CheckHealthAsync(); + + Assert.AreEqual(HealthStatus.Healthy, response.Status); + } } -} +} \ No newline at end of file diff --git a/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.Common/Configuration/EssFulfilmentStorageConfiguration.cs b/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.Common/Configuration/EssFulfilmentStorageConfiguration.cs index 67c4968d8..d460c4146 100644 --- a/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.Common/Configuration/EssFulfilmentStorageConfiguration.cs +++ b/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.Common/Configuration/EssFulfilmentStorageConfiguration.cs @@ -23,5 +23,6 @@ public class EssFulfilmentStorageConfiguration : IEssFulfilmentStorageConfigurat public double SmallExchangeSetSizeInMB { get; set; } public string ExchangeSetTypes { get; set; } public double LargeMediaExchangeSetSizeInMB { get; set; } + public string WebAppVersion { get; set; } } } diff --git a/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.Common/HealthCheck/AzureWebJobsHealthCheckService.cs b/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.Common/HealthCheck/AzureWebJobsHealthCheckService.cs index 5c6e7b8cd..c389a15a1 100644 --- a/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.Common/HealthCheck/AzureWebJobsHealthCheckService.cs +++ b/UKHO.ExchangeSetService.API/UKHO.ExchangeSetService.Common/HealthCheck/AzureWebJobsHealthCheckService.cs @@ -36,15 +36,33 @@ public AzureWebJobsHealthCheckService(IOptions CheckHealthAsync(CancellationToken cancellationToken = default) { string[] exchangeSetTypes = essFulfilmentStorageConfiguration.Value.ExchangeSetTypes.Split(","); + string webAppVersion = essFulfilmentStorageConfiguration.Value.WebAppVersion; + string userNameKey, passwordKey, webJobUri = string.Empty; List webJobs = new List(); foreach (string exchangeSetTypeName in exchangeSetTypes) { Enum.TryParse(exchangeSetTypeName, out ExchangeSetType exchangeSetType); for (int instance = 1; instance <= azureBlobStorageService.GetInstanceCountBasedOnExchangeSetType(exchangeSetType); instance++) { - string userNameKey = $"ess-{webHostEnvironment.EnvironmentName}-{exchangeSetType}-{instance}-webapp-scm-username"; - string passwordKey = $"ess-{webHostEnvironment.EnvironmentName}-{exchangeSetType}-{instance}-webapp-scm-password"; - string webJobUri = $"https://ess-{webHostEnvironment.EnvironmentName}-{exchangeSetType}-{instance}-webapp.scm.azurewebsites.net/api/continuouswebjobs/ESSFulfilmentWebJob"; + if (webAppVersion.ToLowerInvariant() != "v2") + { + userNameKey = + $"ess-{webHostEnvironment.EnvironmentName}-{exchangeSetType}-{instance}-webapp-scm-username"; + passwordKey = + $"ess-{webHostEnvironment.EnvironmentName}-{exchangeSetType}-{instance}-webapp-scm-password"; + webJobUri = + $"https://ess-{webHostEnvironment.EnvironmentName}-{exchangeSetType}-{instance}-webapp.scm.azurewebsites.net/api/continuouswebjobs/ESSFulfilmentWebJob"; + } + else + { + userNameKey = + $"ess-{webHostEnvironment.EnvironmentName}-{exchangeSetType}-{instance}-webapp-v2-scm-username"; + passwordKey = + $"ess-{webHostEnvironment.EnvironmentName}-{exchangeSetType}-{instance}-webapp-v2-scm-password"; + webJobUri = + $"https://ess-{webHostEnvironment.EnvironmentName}-{exchangeSetType}-{instance}-webapp-v2.scm.azurewebsites.net/api/continuouswebjobs/ESSFulfilmentWebJob"; + } + string userPassword = webJobsAccessKeyProvider.GetWebJobsAccessKey(userNameKey) + ":" + webJobsAccessKeyProvider.GetWebJobsAccessKey(passwordKey); userPassword = Convert.ToBase64String(Encoding.Default.GetBytes(userPassword)); diff --git a/azure-pipelines.yml b/azure-pipelines.yml index adbb0439c..d22161786 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -106,96 +106,96 @@ stages: displayName: "Build (inc DependencyChecker, Dotnet Build , dotnet test and publish artifact )" dependsOn: [] jobs: - - job: Dependencychecker - workspace: - clean: all - displayName: "Dependencychecker" - steps: - - task: UseDotNet@2 - displayName: 'Use .NET SDK' - inputs: - packageType: sdk - useGlobalJson: true - workingDirectory: '$(Build.SourcesDirectory)' - - - task: DotNetCoreCLI@2 - displayName: ".Net Core - NuGet restore non test projects only" - inputs: - command: "restore" - projects: | - **/*.csproj - !**/*Tests.csproj - feedsToUse: config - noCache: true - nugetConfigPath: '$(Build.SourcesDirectory)\BuildNuget.config' - workingDirectory: '$(Build.SourcesDirectory)\UKHO.ExchangeSetService.API' - packagesDirectory: '$(Build.SourcesDirectory)\UKHO.ExchangeSetService.API\packages' - - - task: CmdLine@1 - displayName: "Run OWASP Dependency Checker" - inputs: - filename: 'dependency-check.bat' - arguments: '--project "Exchange-Set-Service - $(Build.SourceBranchName)" --scan "$(Build.SourcesDirectory)\UKHO.ExchangeSetService.API" --out "$(Build.ArtifactStagingDirectory)\DCReport" --suppression $(Build.SourcesDirectory)\NVDSuppressions.xml --noupdate' - - - task: PublishBuildArtifacts@1 - displayName: "Publish Artifact: OWASP Dependency Checker Report" - inputs: - PathtoPublish: '$(Build.ArtifactStagingDirectory)\DCReport' - ArtifactName: "OWASP Dependency Checker Report" - - - task: PowerShell@1 - displayName: "Fail Build if Dependency Check Finds Any Vulnerabilities" - inputs: - scriptType: inlineScript - arguments: '-ReportLocation $(Build.ArtifactStagingDirectory)\DCReport\*' - inlineScript: | - param($ReportLocation) - Invoke-VulnerabilityCheck -ReportLocation $ReportLocation - - - job: UnitTestsAndCodeCoverage - workspace: - clean: all - displayName: "Dotnet Test and Publish Code Coverage" - steps: - - task: UseDotNet@2 - displayName: 'Use .NET SDK' - inputs: - packageType: sdk - useGlobalJson: true - workingDirectory: '$(Build.SourcesDirectory)' - - - task: DotNetCoreCLI@2 - displayName: ".Net Core - NuGet restore test projects only" - inputs: - command: "restore" - projects: "**/*Tests.csproj" - feedsToUse: config - noCache: true - nugetConfigPath: '$(Build.SourcesDirectory)\BuildNuget.config' - workingDirectory: '$(Build.SourcesDirectory)\UKHO.ExchangeSetService.API' - packagesDirectory: '$(Build.SourcesDirectory)\UKHO.ExchangeSetService.API\packagesForTests' - - - task: DotNetCoreCLI@2 - displayName: "dotnet test - Perform Unit Tests" - inputs: - command: "test" - projects: "**/*UnitTests.csproj" - arguments: '--configuration $(BuildConfiguration) --settings "$(Build.SourcesDirectory)\test.runsettings" /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura' - publishTestResults: true - testRunTitle: "UnitTests" - - - task: PowerShell@2 - displayName: "Generate code coverage report" - inputs: - targetType: filePath - filePath: '$(Build.SourcesDirectory)\CodeCoverageReport.ps1' - arguments: '-source "$(Build.SourcesDirectory)" -reportFolder "$(Build.ArtifactStagingDirectory)"' + # - job: Dependencychecker + # workspace: + # clean: all + # displayName: "Dependencychecker" + # steps: + # - task: UseDotNet@2 + # displayName: 'Use .NET SDK' + # inputs: + # packageType: sdk + # useGlobalJson: true + # workingDirectory: '$(Build.SourcesDirectory)' + + # - task: DotNetCoreCLI@2 + # displayName: ".Net Core - NuGet restore non test projects only" + # inputs: + # command: "restore" + # projects: | + # **/*.csproj + # !**/*Tests.csproj + # feedsToUse: config + # noCache: true + # nugetConfigPath: '$(Build.SourcesDirectory)\BuildNuget.config' + # workingDirectory: '$(Build.SourcesDirectory)\UKHO.ExchangeSetService.API' + # packagesDirectory: '$(Build.SourcesDirectory)\UKHO.ExchangeSetService.API\packages' + + # - task: CmdLine@1 + # displayName: "Run OWASP Dependency Checker" + # inputs: + # filename: 'dependency-check.bat' + # arguments: '--project "Exchange-Set-Service - $(Build.SourceBranchName)" --scan "$(Build.SourcesDirectory)\UKHO.ExchangeSetService.API" --out "$(Build.ArtifactStagingDirectory)\DCReport" --suppression $(Build.SourcesDirectory)\NVDSuppressions.xml --noupdate' + + # - task: PublishBuildArtifacts@1 + # displayName: "Publish Artifact: OWASP Dependency Checker Report" + # inputs: + # PathtoPublish: '$(Build.ArtifactStagingDirectory)\DCReport' + # ArtifactName: "OWASP Dependency Checker Report" + + # - task: PowerShell@1 + # displayName: "Fail Build if Dependency Check Finds Any Vulnerabilities" + # inputs: + # scriptType: inlineScript + # arguments: '-ReportLocation $(Build.ArtifactStagingDirectory)\DCReport\*' + # inlineScript: | + # param($ReportLocation) + # Invoke-VulnerabilityCheck -ReportLocation $ReportLocation + + # - job: UnitTestsAndCodeCoverage + # workspace: + # clean: all + # displayName: "Dotnet Test and Publish Code Coverage" + # steps: + # - task: UseDotNet@2 + # displayName: 'Use .NET SDK' + # inputs: + # packageType: sdk + # useGlobalJson: true + # workingDirectory: '$(Build.SourcesDirectory)' + + # - task: DotNetCoreCLI@2 + # displayName: ".Net Core - NuGet restore test projects only" + # inputs: + # command: "restore" + # projects: "**/*Tests.csproj" + # feedsToUse: config + # noCache: true + # nugetConfigPath: '$(Build.SourcesDirectory)\BuildNuget.config' + # workingDirectory: '$(Build.SourcesDirectory)\UKHO.ExchangeSetService.API' + # packagesDirectory: '$(Build.SourcesDirectory)\UKHO.ExchangeSetService.API\packagesForTests' + + # - task: DotNetCoreCLI@2 + # displayName: "dotnet test - Perform Unit Tests" + # inputs: + # command: "test" + # projects: "**/*UnitTests.csproj" + # arguments: '--configuration $(BuildConfiguration) --settings "$(Build.SourcesDirectory)\test.runsettings" /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura' + # publishTestResults: true + # testRunTitle: "UnitTests" + + # - task: PowerShell@2 + # displayName: "Generate code coverage report" + # inputs: + # targetType: filePath + # filePath: '$(Build.SourcesDirectory)\CodeCoverageReport.ps1' + # arguments: '-source "$(Build.SourcesDirectory)" -reportFolder "$(Build.ArtifactStagingDirectory)"' - - task: PublishBuildArtifacts@1 - displayName: "Publish Code coverage" - inputs: - PathtoPublish: "$(Build.ArtifactStagingDirectory)/codecoveragereport" - ArtifactName: codecoveragereport + # - task: PublishBuildArtifacts@1 + # displayName: "Publish Code coverage" + # inputs: + # PathtoPublish: "$(Build.ArtifactStagingDirectory)/codecoveragereport" + # ArtifactName: codecoveragereport - job: BuildAndPublishAPI workspace: @@ -336,6 +336,13 @@ stages: SourceFolder: '$(Build.SourcesDirectory)' Contents: 'exchangeSetService_OpenApi_definition.yaml' TargetFolder: '$(Build.SourcesDirectory)\Deployment\src\Modules\APIM' + + - task: CopyFiles@2 + displayName: "Copy OpenAPI spec for new UI API for deployment" + inputs: + SourceFolder: '$(Build.SourcesDirectory)' + Contents: 'exchangeSetService_Ui_OpenApi_definition.yaml' + TargetFolder: '$(Build.SourcesDirectory)\Deployment\src\Modules\APIM' - task: PublishBuildArtifacts@1 displayName: "Publish terraform Artifacts" @@ -463,96 +470,148 @@ stages: - template: Deployment/templates/continuous-deployment-apim.yml parameters: - ContinueEvenIfResourcesAreGettingDestroyed: ${{ parameters.ContinueEvenIfResourcesAreGettingDestroyed }} - AzureSubscription: "Fleet Manager Dev/Test" - TerraformKeyVault: $(APIM_TERRAFORM_KEYVAULT) - APIMResourceGroup: $(APIM_RESOURCE_GROUP_NAME) - APIMServiceInstance: $(APIM_SERVICE_NAME) - tfstateStorageAccountRG: $(APIM_TFSTATE_STORAGE_ACCOUNT_RG) - tfstateStorageAccountName: $(APIM_TFSTATE_STORAGE_ACCOUNT_NAME) + ContinueEvenIfResourcesAreGettingDestroyed: ${{ parameters.ContinueEvenIfResourcesAreGettingDestroyed }} + AzureSubscription: "Fleet Manager Dev/Test" + TerraformKeyVault: $(APIM_TERRAFORM_KEYVAULT) + APIMResourceGroup: $(APIM_RESOURCE_GROUP_NAME) + APIMServiceInstance: $(APIM_SERVICE_NAME) + tfstateStorageAccountRG: $(APIM_TFSTATE_STORAGE_ACCOUNT_RG) + tfstateStorageAccountName: $(APIM_TFSTATE_STORAGE_ACCOUNT_NAME) - - task: DownloadBuildArtifacts@0 - displayName: "Download Functional test Artifact" - inputs: - buildType: 'current' - downloadType: 'single' - artifactName: 'functionaltests' - downloadPath: '$(Build.SourcesDirectory)' + # - task: DownloadBuildArtifacts@0 + # displayName: "Download Functional test Artifact" + # inputs: + # buildType: 'current' + # downloadType: 'single' + # artifactName: 'functionaltests' + # downloadPath: '$(Build.SourcesDirectory)' - - task: DownloadBuildArtifacts@0 - displayName: "Download Terraform Artifact" - inputs: - buildType: 'current' - downloadType: 'single' - artifactName: 'terraformartifact' - downloadPath: '$(Build.SourcesDirectory)' + # - task: DownloadBuildArtifacts@0 + # displayName: "Download Terraform Artifact" + # inputs: + # buildType: 'current' + # downloadType: 'single' + # artifactName: 'terraformartifact' + # downloadPath: '$(Build.SourcesDirectory)' - - task: FileTransform@2 - displayName: "File Transform: functionaltests" - inputs: - folderPath: '$(Build.SourcesDirectory)/functionaltests/' - xmlTransformationRules: - jsonTargetFiles: '**/appsettings.json' + # - task: FileTransform@2 + # displayName: "File Transform: functionaltests" + # inputs: + # folderPath: '$(Build.SourcesDirectory)/functionaltests/' + # xmlTransformationRules: + # jsonTargetFiles: '**/appsettings.json' - - task: UseDotNet@2 - displayName: 'Use .NET SDK' - inputs: - packageType: sdk - useGlobalJson: true - workingDirectory: '$(Build.SourcesDirectory)' + # - task: UseDotNet@2 + # displayName: 'Use .NET SDK' + # inputs: + # packageType: sdk + # useGlobalJson: true + # workingDirectory: '$(Build.SourcesDirectory)' - - task: AzureCLI@2 - displayName: "Swap ESS API and ESS FulfilmentService Configuration AIOEnabled" - condition: always() - inputs: - azureSubscription: "Exchange-Set-Service-Dev-A-008-02" - scriptType: 'pscore' - scriptLocation: 'scriptPath' - scriptPath: "$(Build.SourcesDirectory)/terraformartifact/set_api_webjob_aio_feature_configuration.ps1" - arguments: '-aiocells $(AioConfiguration.AioCells_FT) -aioenabled "true" -resourcegroup $(RESOURCE_GROUP_NAME) -webappname $(WEB_APP_NAME) -fulfilmentwebappsname $(fulfilmentWebAppsName)' + # - task: AzureCLI@2 + # displayName: "Swap ESS API and ESS FulfilmentService Configuration AIOEnabled" + # condition: always() + # inputs: + # azureSubscription: "Exchange-Set-Service-Dev-A-008-02" + # scriptType: 'pscore' + # scriptLocation: 'scriptPath' + # scriptPath: "$(Build.SourcesDirectory)/terraformartifact/set_api_webjob_aio_feature_configuration.ps1" + # arguments: '-aiocells $(AioConfiguration.AioCells_FT) -aioenabled "true" -resourcegroup $(RESOURCE_GROUP_NAME) -webappname $(WEB_APP_NAME) -fulfilmentwebappsname $(fulfilmentWebAppsName)' - - task: DotNetCoreCLI@2 - displayName: "Run Functional tests AIOEnabled" - inputs: - command: "test" - projects: | - **/*FunctionalTest*.dll - !**/*TestAdapter.dll - !**/obj/** - arguments: '--filter Category=SmokeTest-AIOEnabled' - testRunTitle: "Dev-AutomationTests" - workingDirectory: '$(Build.SourcesDirectory)/functionaltests' + # - task: DotNetCoreCLI@2 + # displayName: "Run Functional tests AIOEnabled" + # inputs: + # command: "test" + # projects: | + # **/*FunctionalTest*.dll + # !**/*TestAdapter.dll + # !**/obj/** + # arguments: '--filter Category=SmokeTest-AIOEnabled' + # testRunTitle: "Dev-AutomationTests" + # workingDirectory: '$(Build.SourcesDirectory)/functionaltests' - - task: AzureCLI@2 - displayName: "Swap ESS API and ESS FulfilmentService Configuration AIODisabled" - inputs: - azureSubscription: "Exchange-Set-Service-Dev-A-008-02" - scriptType: 'pscore' - scriptLocation: 'scriptPath' - scriptPath: "$(Build.SourcesDirectory)/terraformartifact/set_api_webjob_aio_feature_configuration.ps1" - arguments: '-aiocells $(AioConfiguration.AioCells_FT) -aioenabled "false" -resourcegroup $(RESOURCE_GROUP_NAME) -webappname $(WEB_APP_NAME) -fulfilmentwebappsname $(fulfilmentWebAppsName)' + # - task: AzureCLI@2 + # displayName: "Swap ESS API and ESS FulfilmentService Configuration AIODisabled" + # inputs: + # azureSubscription: "Exchange-Set-Service-Dev-A-008-02" + # scriptType: 'pscore' + # scriptLocation: 'scriptPath' + # scriptPath: "$(Build.SourcesDirectory)/terraformartifact/set_api_webjob_aio_feature_configuration.ps1" + # arguments: '-aiocells $(AioConfiguration.AioCells_FT) -aioenabled "false" -resourcegroup $(RESOURCE_GROUP_NAME) -webappname $(WEB_APP_NAME) -fulfilmentwebappsname $(fulfilmentWebAppsName)' - - task: DotNetCoreCLI@2 - displayName: "Run Functional tests AIODisabled" - inputs: - command: "test" - projects: | - **/*FunctionalTest*.dll - !**/*TestAdapter.dll - !**/obj/** - arguments: '--filter Category=SmokeTest-AIODisabled' - testRunTitle: "Dev-AutomationTests" - workingDirectory: '$(Build.SourcesDirectory)/functionaltests' + # - task: DotNetCoreCLI@2 + # displayName: "Run Functional tests AIODisabled" + # inputs: + # command: "test" + # projects: | + # **/*FunctionalTest*.dll + # !**/*TestAdapter.dll + # !**/obj/** + # arguments: '--filter Category=SmokeTest-AIODisabled' + # testRunTitle: "Dev-AutomationTests" + # workingDirectory: '$(Build.SourcesDirectory)/functionaltests' - - task: AzureCLI@2 - displayName: "Swap ESS API and ESS FulfilmentService Configuration" - condition: always() - inputs: - azureSubscription: "Exchange-Set-Service-Dev-A-008-02" - scriptType: 'pscore' - scriptLocation: 'scriptPath' - scriptPath: "$(Build.SourcesDirectory)/terraformartifact/set_api_webjob_aio_feature_configuration.ps1" - arguments: '-aiocells $(AioConfiguration.AioCells) -aioenabled $(AioConfiguration.AioEnabled) -resourcegroup $(RESOURCE_GROUP_NAME) -webappname $(WEB_APP_NAME) -fulfilmentwebappsname $(fulfilmentWebAppsName)' + # - task: AzureCLI@2 + # displayName: "Swap ESS API and ESS FulfilmentService Configuration" + # condition: always() + # inputs: + # azureSubscription: "Exchange-Set-Service-Dev-A-008-02" + # scriptType: 'pscore' + # scriptLocation: 'scriptPath' + # scriptPath: "$(Build.SourcesDirectory)/terraformartifact/set_api_webjob_aio_feature_configuration.ps1" + # arguments: '-aiocells $(AioConfiguration.AioCells) -aioenabled $(AioConfiguration.AioEnabled) -resourcegroup $(RESOURCE_GROUP_NAME) -webappname $(WEB_APP_NAME) -fulfilmentwebappsname $(fulfilmentWebAppsName)' + + + - deployment: DevDeployApp2 + dependsOn: DevDeployApp + displayName: "Dev - deploy terraform and dotnet App for FSS UI" + environment: "Ess-Dev" + pool: $(DeploymentPool) + container: ${{variables.Container}} + workspace: + clean: all + variables: + - group: "ESS-Deployment-Variables-DEV" + - group: "ESS-Dev2-Variables" + - name: "ESSAzureADConfiguration.ClientId" + value: $(ESSClientId) + - name: "ESSAzureADConfiguration.TenantId" + value: $(TenantId) + - name: "EssAuthorizationConfiguration.TenantId" + value: $(TenantId) + - name: "EssAuthorizationConfiguration.AutoTestClientId" + value: $(AutoTestClientId_Authed) + - name: "EssAuthorizationConfiguration.AutoTestClientSecret" + value: $(AutoTestClientSecret_Authed) + - name: "EssAuthorizationConfiguration.EssClientId" + value: $(ESSClientId) + - name: "EssAuthorizationConfiguration.AutoTestClientIdNoAuth" + value: $(AutoTestClientId_NoAuth) + - name: "EssAuthorizationConfiguration.AutoTestClientSecretNoAuth" + value: $(AutoTestClientSecret_NoAuth) + - name: "AzureAdB2CTestConfiguration.ClientSecret" + value: $(AUTOTEST-ESS-SECRET) + strategy: + runOnce: + deploy: + steps: + - checkout: self + submodules: recursive + + - template: Deployment/templates/continuous-deployment-v2.yml + parameters: + ContinueEvenIfResourcesAreGettingDestroyed: ${{ parameters.ContinueEvenIfResourcesAreGettingDestroyed }} + AzureSubscription: "Exchange-Set-Service-Dev-A-008-02" + + - template: Deployment/templates/continuous-deployment-apim-v2.yml + parameters: + ContinueEvenIfResourcesAreGettingDestroyed: ${{ parameters.ContinueEvenIfResourcesAreGettingDestroyed }} + AzureSubscription: "Fleet Manager Dev/Test" + TerraformKeyVault: $(APIM_TERRAFORM_KEYVAULT) + APIMResourceGroup: $(APIM_RESOURCE_GROUP_NAME) + APIMServiceInstance: $(APIM_SERVICE_NAME) + tfstateStorageAccountRG: $(APIM_TFSTATE_STORAGE_ACCOUNT_RG) + tfstateStorageAccountName: $(APIM_TFSTATE_STORAGE_ACCOUNT_NAME) - stage: QCdeploy dependsOn: @@ -692,10 +751,11 @@ stages: - stage: QAdeploy dependsOn: - - Devdeploy - - QCdeploy + - PERFORM_DEPENDENCYCHECK_DOTNETBUILD_DOTNETTEST_AND_PUBLISH + # - Devdeploy + # - QCdeploy displayName: QAdeploy (inc terraform, webapp deploy) - condition: and(succeeded(), or(eq(variables['Build.SourceBranch'], 'refs/heads/main'),startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'))) + #condition: and(succeeded(), or(eq(variables['Build.SourceBranch'], 'refs/heads/main'),startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'))) jobs: - deployment: QADeployApp displayName: QA - deploy terraform and dotnet App @@ -747,92 +807,145 @@ stages: tfstateStorageAccountRG: $(APIM_TFSTATE_STORAGE_ACCOUNT_RG) tfstateStorageAccountName: $(APIM_TFSTATE_STORAGE_ACCOUNT_NAME) - - task: DownloadBuildArtifacts@0 - displayName: "Download Functional test Artifact" - inputs: - buildType: 'current' - downloadType: 'single' - artifactName: 'functionaltests' - downloadPath: '$(Build.SourcesDirectory)' + # - task: DownloadBuildArtifacts@0 + # displayName: "Download Functional test Artifact" + # inputs: + # buildType: 'current' + # downloadType: 'single' + # artifactName: 'functionaltests' + # downloadPath: '$(Build.SourcesDirectory)' - - task: DownloadBuildArtifacts@0 - displayName: "Download Terraform Artifact" - inputs: - buildType: 'current' - downloadType: 'single' - artifactName: 'terraformartifact' - downloadPath: '$(Build.SourcesDirectory)' + # - task: DownloadBuildArtifacts@0 + # displayName: "Download Terraform Artifact" + # inputs: + # buildType: 'current' + # downloadType: 'single' + # artifactName: 'terraformartifact' + # downloadPath: '$(Build.SourcesDirectory)' - - task: FileTransform@2 - displayName: "File Transform: functionaltests" - inputs: - folderPath: '$(Build.SourcesDirectory)/functionaltests/' - xmlTransformationRules: - jsonTargetFiles: '**/appsettings.json' + # - task: FileTransform@2 + # displayName: "File Transform: functionaltests" + # inputs: + # folderPath: '$(Build.SourcesDirectory)/functionaltests/' + # xmlTransformationRules: + # jsonTargetFiles: '**/appsettings.json' - - task: UseDotNet@2 - displayName: 'Use .NET SDK' - inputs: - packageType: sdk - useGlobalJson: true - workingDirectory: '$(Build.SourcesDirectory)' + # - task: UseDotNet@2 + # displayName: 'Use .NET SDK' + # inputs: + # packageType: sdk + # useGlobalJson: true + # workingDirectory: '$(Build.SourcesDirectory)' - - task: AzureCLI@2 - displayName: "Swap ESS API and ESS FulfilmentService Configuration AIOEnabled" - condition: always() - inputs: - azureSubscription: "Exchange-Set-Service-QA-A-008-02" - scriptType: 'pscore' - scriptLocation: 'scriptPath' - scriptPath: "$(Build.SourcesDirectory)/terraformartifact/set_api_webjob_aio_feature_configuration.ps1" - arguments: '-aiocells $(AioConfiguration.AioCells_FT) -aioenabled "true" -resourcegroup $(RESOURCE_GROUP_NAME) -webappname $(WEB_APP_NAME) -fulfilmentwebappsname $(fulfilmentWebAppsName)' + # - task: AzureCLI@2 + # displayName: "Swap ESS API and ESS FulfilmentService Configuration AIOEnabled" + # condition: always() + # inputs: + # azureSubscription: "Exchange-Set-Service-QA-A-008-02" + # scriptType: 'pscore' + # scriptLocation: 'scriptPath' + # scriptPath: "$(Build.SourcesDirectory)/terraformartifact/set_api_webjob_aio_feature_configuration.ps1" + # arguments: '-aiocells $(AioConfiguration.AioCells_FT) -aioenabled "true" -resourcegroup $(RESOURCE_GROUP_NAME) -webappname $(WEB_APP_NAME) -fulfilmentwebappsname $(fulfilmentWebAppsName)' - - task: DotNetCoreCLI@2 - displayName: "Run Functional tests AIOEnabled" - inputs: - command: "test" - projects: | - **/*FunctionalTest*.dll - !**/*TestAdapter.dll - !**/obj/** - arguments: '--filter Category=SmokeTest-AIOEnabled' - testRunTitle: "QA-AutomationTests" - workingDirectory: '$(Build.SourcesDirectory)/functionaltests' + # - task: DotNetCoreCLI@2 + # displayName: "Run Functional tests AIOEnabled" + # inputs: + # command: "test" + # projects: | + # **/*FunctionalTest*.dll + # !**/*TestAdapter.dll + # !**/obj/** + # arguments: '--filter Category=SmokeTest-AIOEnabled' + # testRunTitle: "QA-AutomationTests" + # workingDirectory: '$(Build.SourcesDirectory)/functionaltests' - - task: AzureCLI@2 - displayName: "Swap ESS API and ESS FulfilmentService Configuration AIODisabled" - inputs: - azureSubscription: "Exchange-Set-Service-QA-A-008-02" - scriptType: 'pscore' - scriptLocation: 'scriptPath' - scriptPath: "$(Build.SourcesDirectory)/terraformartifact/set_api_webjob_aio_feature_configuration.ps1" - arguments: '-aiocells $(AioConfiguration.AioCells_FT) -aioenabled "false" -resourcegroup $(RESOURCE_GROUP_NAME) -webappname $(WEB_APP_NAME) -fulfilmentwebappsname $(fulfilmentWebAppsName)' + # - task: AzureCLI@2 + # displayName: "Swap ESS API and ESS FulfilmentService Configuration AIODisabled" + # inputs: + # azureSubscription: "Exchange-Set-Service-QA-A-008-02" + # scriptType: 'pscore' + # scriptLocation: 'scriptPath' + # scriptPath: "$(Build.SourcesDirectory)/terraformartifact/set_api_webjob_aio_feature_configuration.ps1" + # arguments: '-aiocells $(AioConfiguration.AioCells_FT) -aioenabled "false" -resourcegroup $(RESOURCE_GROUP_NAME) -webappname $(WEB_APP_NAME) -fulfilmentwebappsname $(fulfilmentWebAppsName)' - - task: DotNetCoreCLI@2 - displayName: "Run Functional tests AIODisabled" - inputs: - command: "test" - projects: | - **/*FunctionalTest*.dll - !**/*TestAdapter.dll - !**/obj/** - arguments: '--filter Category=SmokeTest-AIODisabled' - testRunTitle: "QA-AutomationTests" - workingDirectory: '$(Build.SourcesDirectory)/functionaltests' + # - task: DotNetCoreCLI@2 + # displayName: "Run Functional tests AIODisabled" + # inputs: + # command: "test" + # projects: | + # **/*FunctionalTest*.dll + # !**/*TestAdapter.dll + # !**/obj/** + # arguments: '--filter Category=SmokeTest-AIODisabled' + # testRunTitle: "QA-AutomationTests" + # workingDirectory: '$(Build.SourcesDirectory)/functionaltests' - - task: AzureCLI@2 - displayName: "Swap ESS API and ESS FulfilmentService Configuration" - condition: always() - inputs: - azureSubscription: "Exchange-Set-Service-QA-A-008-02" - scriptType: 'pscore' - scriptLocation: 'scriptPath' - scriptPath: "$(Build.SourcesDirectory)/terraformartifact/set_api_webjob_aio_feature_configuration.ps1" - arguments: '-aiocells $(AioConfiguration.AioCells) -aioenabled $(AioConfiguration.AioEnabled) -resourcegroup $(RESOURCE_GROUP_NAME) -webappname $(WEB_APP_NAME) -fulfilmentwebappsname $(fulfilmentWebAppsName)' + # - task: AzureCLI@2 + # displayName: "Swap ESS API and ESS FulfilmentService Configuration" + # condition: always() + # inputs: + # azureSubscription: "Exchange-Set-Service-QA-A-008-02" + # scriptType: 'pscore' + # scriptLocation: 'scriptPath' + # scriptPath: "$(Build.SourcesDirectory)/terraformartifact/set_api_webjob_aio_feature_configuration.ps1" + # arguments: '-aiocells $(AioConfiguration.AioCells) -aioenabled $(AioConfiguration.AioEnabled) -resourcegroup $(RESOURCE_GROUP_NAME) -webappname $(WEB_APP_NAME) -fulfilmentwebappsname $(fulfilmentWebAppsName)' + + - deployment: QADeployApp2 + dependsOn: QADeployApp + displayName: "QA - deploy terraform and dotnet App for FSS UI" + environment: "Ess-Qa" + pool: $(DeploymentPool) + container: ${{variables.Container}} + workspace: + clean: all + variables: + - group: "ESS-Deployment-Variables-QA" + - group: "ESS-QA2-Variables" + - name: "ESSAzureADConfiguration.ClientId" + value: $(ESSClientId) + - name: "ESSAzureADConfiguration.TenantId" + value: $(TenantId) + - name: "EssAuthorizationConfiguration.TenantId" + value: $(TenantId) + - name: "EssAuthorizationConfiguration.AutoTestClientId" + value: $(AutoTestClientId_Authed) + - name: "EssAuthorizationConfiguration.AutoTestClientSecret" + value: $(AutoTestClientSecret_Authed) + - name: "EssAuthorizationConfiguration.EssClientId" + value: $(ESSClientId) + - name: "EssAuthorizationConfiguration.AutoTestClientIdNoAuth" + value: $(AutoTestClientId_NoAuth) + - name: "EssAuthorizationConfiguration.AutoTestClientSecretNoAuth" + value: $(AutoTestClientSecret_NoAuth) + - name: "AzureAdB2CTestConfiguration.ClientSecret" + value: $(AUTOTEST-ESS-SECRET) + strategy: + runOnce: + deploy: + steps: + - checkout: self + submodules: recursive + + - template: Deployment/templates/continuous-deployment-v2.yml + parameters: + ContinueEvenIfResourcesAreGettingDestroyed: ${{ parameters.ContinueEvenIfResourcesAreGettingDestroyed }} + AzureSubscription: "Exchange-Set-Service-QA-A-008-02" + + - template: Deployment/templates/continuous-deployment-apim-v2.yml + parameters: + ContinueEvenIfResourcesAreGettingDestroyed: ${{ parameters.ContinueEvenIfResourcesAreGettingDestroyed }} + AzureSubscription: "Fleet Manager Dev/Test" + TerraformKeyVault: $(APIM_TERRAFORM_KEYVAULT) + APIMResourceGroup: $(APIM_RESOURCE_GROUP_NAME) + APIMServiceInstance: $(APIM_SERVICE_NAME) + tfstateStorageAccountRG: $(APIM_TFSTATE_STORAGE_ACCOUNT_RG) + tfstateStorageAccountName: $(APIM_TFSTATE_STORAGE_ACCOUNT_NAME) - job: Run_ADDS_E2E_tests displayName: Run ADDS E2E tests - dependsOn: QADeployApp + dependsOn: + - QADeployApp + - QADeployApp2 pool: $(DeploymentPool) variables: - group: "ADDS-E2E" @@ -884,10 +997,45 @@ stages: APIMServiceInstance: $(APIM_SERVICE_NAME) tfstateStorageAccountRG: $(APIM_TFSTATE_STORAGE_ACCOUNT_RG) tfstateStorageAccountName: $(APIM_TFSTATE_STORAGE_ACCOUNT_NAME) + + - deployment: LiveDeployApp2 + dependsOn: LiveDeployApp + displayName: "Live - deploy terraform and dotnet App for FSS UI" + environment: "Ess-Live" + pool: $(DeploymentPool) + container: ${{variables.Container}} + workspace: + clean: all + variables: + - group: "ESS-Deployment-Variables-LIVE" + - group: "ESS-Live2-Variables" + - name: "ESSAzureADConfiguration.ClientId" + value: $(ESSClientId) + - name: "ESSAzureADConfiguration.TenantId" + value: $(TenantId) + strategy: + runOnce: + deploy: + steps: + - template: Deployment/templates/continuous-deployment-v2.yml + parameters: + ContinueEvenIfResourcesAreGettingDestroyed: ${{ parameters.ContinueEvenIfResourcesAreGettingDestroyed }} + AzureSubscription: "Exchange-Set-Service-Live-A-008-02" + + - template: Deployment/templates/continuous-deployment-apim-v2.yml + parameters: + ContinueEvenIfResourcesAreGettingDestroyed: ${{ parameters.ContinueEvenIfResourcesAreGettingDestroyed }} + AzureSubscription: "UKHO-APIM-Live" + TerraformKeyVault: $(APIM_TERRAFORM_KEYVAULT) + APIMResourceGroup: $(APIM_RESOURCE_GROUP_NAME) + APIMServiceInstance: $(APIM_SERVICE_NAME) + tfstateStorageAccountRG: $(APIM_TFSTATE_STORAGE_ACCOUNT_RG) + tfstateStorageAccountName: $(APIM_TFSTATE_STORAGE_ACCOUNT_NAME) - job: PostDeploymentActions dependsOn: - - LiveDeployApp + #- LiveDeployApp + - LiveDeployApp2 pool: $(WindowPool) displayName: Post Deployment Actions steps: diff --git a/exchangeSetService_Ui_OpenApi_definition.yaml b/exchangeSetService_Ui_OpenApi_definition.yaml new file mode 100644 index 000000000..823e0c6ce --- /dev/null +++ b/exchangeSetService_Ui_OpenApi_definition.yaml @@ -0,0 +1,352 @@ +openapi: "3.0.0" +info: + version: "0.3" + title: Exchange Set Service UI API + description: | + This API is for the Exchange Set Service UI. + contact: + name: Martin Rock-Evans + email: martin.rock-evans@ukho.gov.uk + +externalDocs: + url: https://github.com/UKHO/exchange-set-service + +servers: + - url: https://exchangeset.admiralty.co.uk/avcsData/[version]/ + +security: + - jwtBearerAuth: [] + +paths: + /productInformation/productIdentifiers: + post: + summary: Provide ENC information from sales catalog service. + + operationId: postProductIdentifiers + + description: | + Given a list of ENC name identifiers, return all the versions of the ENCs from sales catalog service. + + requestBody: + description: | + The JSON body containing product identifiers. + content: + application/json: + schema: + $ref: "#/components/schemas/productIdentifiers" + example: ["GB102505", "GB100160", "AU334550"] + + responses: + "200": + description: A JSON body that containing the information of ENCs. + content: + application/json: + schema: + $ref: "#/components/schemas/scsResponse" + + "400": + description: Bad request. + content: + application/json: + schema: + $ref: "#/components/schemas/errorDescription" + + "401": + $ref: "#/components/responses/unauthorised" + + "403": + $ref: "#/components/responses/forbidden" + + "429": + $ref: "#/components/responses/tooManyRequests" + + "500": + $ref: "#/components/responses/internalServerError" + + + /productInformation: + get: + summary: Get all releasable changes to products since a date + description: | + Given a datetime, get all ENC versions that have been issued since that datetime. + + operationId: getProducts + + parameters: + - $ref: "#/components/parameters/sinceDateTime" + + responses: + "200": + description: A JSON body of product objects + headers: + Last-Modified: + schema: + $ref: "#/components/schemas/Date-Header" + content: + application/json: + schema: + $ref: "#/components/schemas/scsResponse" + + "304": + description: Not modified. + headers: + Last-Modified: + schema: + $ref: "#/components/schemas/Date-Header" + + "400": + description: Bad request. + content: + application/json: + schema: + $ref: "#/components/schemas/errorDescription" + + "401": + $ref: "#/components/responses/unauthorised" + + "403": + $ref: "#/components/responses/forbidden" + + "429": + $ref: "#/components/responses/tooManyRequests" + + "500": + $ref: "#/components/responses/internalServerError" + + +components: + ################################################################################ + # Parameter Definitions # + ################################################################################ + + parameters: + sinceDateTime: + in: query + name: sinceDateTime + required: true + description: | + The date and time from which changes are requested. Any changes since the date will be returned. The date is in RFC 1123 format. The date and time must be within 28 days and cannot be in future. + schema: + type: string + format: date-time + example: Wed, 21 Oct 2015 07:28:00 GMT + + ################################################################################ + # Common Response Definitions # + ################################################################################ + + responses: + unauthorised: + description: Unauthorised - either you have not provided any credentials, or your credentials are not recognised. + + forbidden: + description: Forbidden - you have been authorised, but you are not allowed to access this resource. + + tooManyRequests: + description: You have sent too many requests in a given amount of time. Please back-off for the time in the Retry-After header (in seconds) and try again. + headers: + Retry-After: + schema: + type: integer + description: Specifies the time you should wait in seconds before retrying. + + internalServerError: + description: Internal Server Error. + content: + application/json: + schema: + $ref: "#/components/schemas/DefaultErrorResponse" + + ################################################################################ + # Object Definitions # + ################################################################################ + + schemas: + #################################### + # Request Objects # + #################################### + + productIdentifiers: + type: array + items: + type: string + + #################################### + # Response Objects # + #################################### + + scsResponse: + type: object + required: + - "products" + - "productCounts" + properties: + products: + type: array + items: + type: object + required: + - "productName" + - "editionNumber" + - "updateNumbers" + - "fileSize" + properties: + productName: + type: string + description: The unique product identifiers + example: "GB102505" + editionNumber: + type: integer + description: The edition number + example: 1 + updateNumbers: + type: array + description: an array of update numbers + items: + type: integer + description: The update number, including update 0 if relevant + example: [0,1,2] + dates: + type: array + items: + type: object + description: issue and update dates + properties: + updateNumber: + type: integer + description: The update number, including update 0 if relevant + updateApplicationDate: + type: string + format: date-time + description: | + The update application date for the catalog.031 UADT data field + The base cell issue date or, for re-issues, the issue date of the previous update + This is optional if not relevant + example: "2019-10-27T00:00:00Z" + issueDate: + type: string + format: date-time + description: | + The issue date for the catalog.031 ISDT data field + example: "2019-10-27T00:00:00Z" + cancellation: + type: object + description: The details of the cancellation, if one exists + properties: + editionNumber: + type: integer + description: The edition number of the cancellation, i.e. 0 + updateNumber: + type: integer + description: The cancellation update number + example: {"editionNumber": 0, "updateNumber": 8} + fileSize: + type: integer + description: The total file size in bytes of all the files for this product + example: 2012 + ignoreCache: + type: boolean + bundle: + type: array + description: | + Collection of physical bundles that are associated with the latest update of this product + items: + type: object + properties: + bundleType: + type: string + description: | + Media type of the bundle, which can be one of the following values:- DVD + example: "DVD" + location: + type: string + description: | + DVDs: This field is divided into two subfields delimited by a semi colon. + The first subfield contains the media number ID and the second the exchange set number. + The Media ID is designated with a M followed by a number. + + Examples: + - base cell: "M1;B3", + - updates: "M2;U1" + example: "M1;B3" + productCounts: + type: object + required: + - "requestedProductsNotReturned" + properties: + requestedProductCount: + type: integer + description: number of products explicitly requested. + returnedProductCount: + type: integer + description: number of products that have data included in the produced exchange set. + requestedProductsAlreadyUpToDateCount: + type: integer + requestedProductsNotReturned: + type: array + description: | + Where a requested product is not included in the return, the product will be listed in the requestedProductNotReturned portion of the response along with a reason. The reason will be one of: + * productWithdrawn (the product has been withdrawn from the AVCS service) + * invalidProduct (the product is not part of the AVCS Service, i.e. is an invalid or unknown ENC) + * noDataAvailableForCancelledProduct (the product has been cancelled, and is beyond the retention period. Cancelled cells within the retention period will be returned with the cancellation data in the exchange set) + * duplicateProduct (the product was included in the request more than once) + items: + type: object + required: + - "productName" + - "reason" + properties: + productName: + type: string + example: "GB102505" + reason: + type: string + enum: [productWithdrawn, invalidProduct, noDataAvailableForCancelledProduct, duplicateProduct] + + Date-Header: + type: string + format: date-time + description: | + Returns the current date and time on the server and should be used in subsequent requests to the productData operation to ensure that there are no gaps due to minor time difference between your own and UKHO systems. The date format is in RFC 1123 format. + example: Wed, 21 Oct 2015 07:28:00 GMT + + #################################### + # Error Response Objects # + #################################### + + DefaultErrorResponse: + type: object + title: Error + properties: + correlationId: + type: string + detail: + type: string + + errorDescription: + type: object + properties: + correlationId: + type: string + errors: + type: array + items: + $ref: "#/components/schemas/fieldError" + + fieldError: + type: object + properties: + source: + type: string + description: + type: string + + #################################### + # Security Objects # + #################################### + + securitySchemes: + jwtBearerAuth: + type: http + scheme: bearer + bearerFormat: JWT \ No newline at end of file