diff --git a/.gitignore b/.gitignore index 637870b..cc57eb8 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,10 @@ # Others .DS_Store + +# Any internal terraform files +**/.terraform* +**/terraform.tfstate +**/terraform.tfstate.backup +test/terraform_linux_vm/**/*.pem + diff --git a/test/terraform_linux_vm/centos/main.tf b/test/terraform_linux_vm/centos/main.tf new file mode 100644 index 0000000..3e2043d --- /dev/null +++ b/test/terraform_linux_vm/centos/main.tf @@ -0,0 +1,86 @@ +module "dependencies" { + source = "../module_vm/dependencies" + allowed_ips = var.allowed_ips +} + + +# Agreement of OS offer +resource "azurerm_marketplace_agreement" "this" { + publisher = "procomputers" + offer = var.os_name + plan = var.os_name +} + +# Create virtual machine +resource "azurerm_linux_virtual_machine" "rpm_vm" { + depends_on = [module.dependencies ,azurerm_marketplace_agreement.this] + + name = "${module.dependencies.random_pet-tf_resource_prefix-id}_VM" + location = module.dependencies.azurerm_resource_group-rg-location + resource_group_name = module.dependencies.azurerm_resource_group-rg-name + network_interface_ids = [module.dependencies.azurerm_network_interface-rpm_tf_nic-id] + size = var.vm_size + + os_disk { + name = "${module.dependencies.random_pet-tf_resource_prefix-id}_OsDisk" + caching = "ReadWrite" + storage_account_type = "Premium_LRS" + } + + plan { + name = var.os_name + product = var.os_name + publisher = "procomputers" + } + + source_image_reference { + publisher = var.os_publisher + offer = var.os_name + sku = var.os_name + version = var.os_version + } + + computer_name = replace(module.dependencies.random_pet-tf_resource_prefix-id, "_", "") + admin_username = var.username + + admin_ssh_key { + username = var.username + public_key = jsondecode(module.dependencies.azapi_resource_action-ssh_public_key_gen-output).publicKey + } + + boot_diagnostics { + storage_account_uri = module.dependencies.azurerm_storage_account-rpm_storage_account-primary_blob_endpoint + } + + connection { + type = "ssh" + user = var.username + private_key = jsondecode(module.dependencies.azapi_resource_action-ssh_public_key_gen-output).privateKey + host = self.public_ip_address + } + + provisioner "file" { + source = "../module_vm/install_redhat.sh" + destination = "install_redhat.sh" + } + + provisioner "remote-exec" { + inline = [ + "sudo yum install -y tmux", + "chmod u+x install_*.sh", + "tmux new-session \\; send-keys './install_redhat.sh' C-m \\; detach-client" + ] + } +} + +output "public_ip_address" { + value = azurerm_linux_virtual_machine.rpm_vm.public_ip_address +} + +output "ssh_command_to_connect" { + value = "ssh -i ${module.dependencies.local_sensitive_file-ssh_private_key-filename} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no matthieu@${azurerm_linux_virtual_machine.rpm_vm.public_ip_address}" +} + +output "scp_command_to_push_rpm" { + value = "scp -i ${module.dependencies.local_sensitive_file-ssh_private_key-filename} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ../../../apim/4.x/graviteeio-apim-*-4x*.rpm matthieu@${azurerm_linux_virtual_machine.rpm_vm.public_ip_address}:." +} diff --git a/test/terraform_linux_vm/centos/providers.tf b/test/terraform_linux_vm/centos/providers.tf new file mode 100644 index 0000000..15e1f30 --- /dev/null +++ b/test/terraform_linux_vm/centos/providers.tf @@ -0,0 +1,15 @@ +terraform { + required_version = ">=1.7" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~>3.94" + } + } +} + +provider "azurerm" { + features {} + subscription_id = "02ae5fba-84b0-443a-9df6-9be92297c139" // Gravitee-SaaS +} diff --git a/test/terraform_linux_vm/centos/variables.tf b/test/terraform_linux_vm/centos/variables.tf new file mode 100644 index 0000000..c339a08 --- /dev/null +++ b/test/terraform_linux_vm/centos/variables.tf @@ -0,0 +1,33 @@ +variable "allowed_ips" { + type = string + description = "Used to filter IP which have access to the Virtual Machine, could be a prefix, CIDR or a match like `*`" + default = "*" +} + +variable "username" { + type = string + description = "The username for the local account that will be created on the new VM." + default = "azureadmin" +} + +variable "vm_size" { + type = string + description = "VM size [Standard_DS1_v2,Standard_DS2_v3,Standard_D2ads_v5]" + default = "Standard_D2ads_v5" +} +variable "os_publisher" { + type = string + description = "Operating System Publisher [RedHat,SUSE]" + default = "procomputers" +} +variable "os_name" { + type = string + description = "Operating System Offer [centos-stream-9-minimal,centos-7-minimal]" + default = "centos-stream-9-minimal" +} +variable "os_version" { + type = string + description = "Operating System Version [latest,8.0.7]" + default = "latest" +} + diff --git a/test/terraform_linux_vm/module_vm/dependencies/network.tf b/test/terraform_linux_vm/module_vm/dependencies/network.tf new file mode 100644 index 0000000..cccb2cf --- /dev/null +++ b/test/terraform_linux_vm/module_vm/dependencies/network.tf @@ -0,0 +1,84 @@ +# Create virtual network +resource "azurerm_virtual_network" "rpm_network" { + depends_on = [data.azurerm_resource_group.rg] + name = "${random_pet.tf_resource_prefix.id}_Vnet" + address_space = ["10.0.0.0/16"] + location = data.azurerm_resource_group.rg.location + resource_group_name = data.azurerm_resource_group.rg.name +} + +# Create subnet +resource "azurerm_subnet" "rpm_subnet" { + depends_on = [data.azurerm_resource_group.rg, random_pet.tf_resource_prefix] + name = "${random_pet.tf_resource_prefix.id}_Subnet" + resource_group_name = data.azurerm_resource_group.rg.name + virtual_network_name = azurerm_virtual_network.rpm_network.name + address_prefixes = ["10.0.1.0/24"] +} + +# Create public IPs +resource "azurerm_public_ip" "rpm_public_ip" { + depends_on = [data.azurerm_resource_group.rg, random_pet.tf_resource_prefix] + name = "${random_pet.tf_resource_prefix.id}_PublicIP" + location = data.azurerm_resource_group.rg.location + resource_group_name = data.azurerm_resource_group.rg.name + allocation_method = "Dynamic" +} + +# Create Network Security Group and rule +resource "azurerm_network_security_group" "rpm_tf_nsg" { + depends_on = [data.azurerm_resource_group.rg, random_pet.tf_resource_prefix] + name = "${random_pet.tf_resource_prefix.id}_NetworkSecurityGroup" + location = data.azurerm_resource_group.rg.location + resource_group_name = data.azurerm_resource_group.rg.name + + security_rule { + name = "SSH" + priority = 1001 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = var.allowed_ips + destination_address_prefix = "*" + } + security_rule { + name = "APIM" + priority = 1101 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "8080-8085" + source_address_prefix = var.allowed_ips + destination_address_prefix = "*" + } +} + +# Create network interface +resource "azurerm_network_interface" "rpm_tf_nic" { + depends_on = [ + data.azurerm_resource_group.rg, + random_pet.tf_resource_prefix, + azurerm_subnet.rpm_subnet, + azurerm_public_ip.rpm_public_ip + ] + name = "${random_pet.tf_resource_prefix.id}_NIC" + location = data.azurerm_resource_group.rg.location + resource_group_name = data.azurerm_resource_group.rg.name + + ip_configuration { + name = "${random_pet.tf_resource_prefix.id}_nic_configuration" + subnet_id = azurerm_subnet.rpm_subnet.id + private_ip_address_allocation = "Dynamic" + public_ip_address_id = azurerm_public_ip.rpm_public_ip.id + } +} + +# Connect the security group to the network interface +resource "azurerm_network_interface_security_group_association" "rpm_nic_sg_asso" { + depends_on = [azurerm_network_interface.rpm_tf_nic, azurerm_network_security_group.rpm_tf_nsg] + network_interface_id = azurerm_network_interface.rpm_tf_nic.id + network_security_group_id = azurerm_network_security_group.rpm_tf_nsg.id +} diff --git a/test/terraform_linux_vm/module_vm/dependencies/outputs.tf b/test/terraform_linux_vm/module_vm/dependencies/outputs.tf new file mode 100644 index 0000000..0582de5 --- /dev/null +++ b/test/terraform_linux_vm/module_vm/dependencies/outputs.tf @@ -0,0 +1,27 @@ +output "random_pet-tf_resource_prefix-id" { + value = random_pet.tf_resource_prefix.id +} + +output "azurerm_resource_group-rg-location" { + value = data.azurerm_resource_group.rg.location +} + +output "azurerm_resource_group-rg-name" { + value = data.azurerm_resource_group.rg.name +} + +output "azurerm_network_interface-rpm_tf_nic-id" { + value = azurerm_network_interface.rpm_tf_nic.id +} + +output "azapi_resource_action-ssh_public_key_gen-output" { + value = azapi_resource_action.ssh_public_key_gen.output +} + +output "azurerm_storage_account-rpm_storage_account-primary_blob_endpoint" { + value = azurerm_storage_account.rpm_storage_account.primary_blob_endpoint +} + +output "local_sensitive_file-ssh_private_key-filename" { + value = local_sensitive_file.ssh_private_key.filename +} diff --git a/test/terraform_linux_vm/module_vm/dependencies/providers.tf b/test/terraform_linux_vm/module_vm/dependencies/providers.tf new file mode 100644 index 0000000..956828b --- /dev/null +++ b/test/terraform_linux_vm/module_vm/dependencies/providers.tf @@ -0,0 +1,23 @@ +terraform { + required_version = ">=1.7" + + required_providers { + azapi = { + source = "azure/azapi" + version = "~>1.12.1" + } + azurerm = { + source = "hashicorp/azurerm" + version = "~>3.94" + } + random = { + source = "hashicorp/random" + version = "~>3.6" + } + } +} + +provider "azurerm" { + features {} + subscription_id = "02ae5fba-84b0-443a-9df6-9be92297c139" // Gravitee-SaaS +} diff --git a/test/terraform_linux_vm/module_vm/dependencies/random.tf b/test/terraform_linux_vm/module_vm/dependencies/random.tf new file mode 100644 index 0000000..fc58e80 --- /dev/null +++ b/test/terraform_linux_vm/module_vm/dependencies/random.tf @@ -0,0 +1,14 @@ +resource "random_pet" "tf_resource_prefix" { + prefix = "rpm" + separator = "_" +} + +# Generate random text for a unique storage account name +resource "random_id" "random_id" { + keepers = { + # Generate a new ID only when a new resource group is defined + resource_group = data.azurerm_resource_group.rg.name + } + + byte_length = 8 +} diff --git a/test/terraform_linux_vm/module_vm/dependencies/resource_group.tf b/test/terraform_linux_vm/module_vm/dependencies/resource_group.tf new file mode 100644 index 0000000..b169a7c --- /dev/null +++ b/test/terraform_linux_vm/module_vm/dependencies/resource_group.tf @@ -0,0 +1,3 @@ +data "azurerm_resource_group" "rg" { + name = "gravitee-rpm-dev" +} diff --git a/test/terraform_linux_vm/module_vm/dependencies/ssh.tf b/test/terraform_linux_vm/module_vm/dependencies/ssh.tf new file mode 100644 index 0000000..d1b19e7 --- /dev/null +++ b/test/terraform_linux_vm/module_vm/dependencies/ssh.tf @@ -0,0 +1,29 @@ +resource "random_pet" "ssh_key_name" { + prefix = "ssh" + separator = "" +} + +resource "azapi_resource_action" "ssh_public_key_gen" { + depends_on = [azapi_resource.ssh_public_key] + type = "Microsoft.Compute/sshPublicKeys@2022-11-01" + resource_id = azapi_resource.ssh_public_key.id + action = "generateKeyPair" + method = "POST" + + response_export_values = ["publicKey", "privateKey"] +} + +resource "azapi_resource" "ssh_public_key" { + depends_on = [random_pet.ssh_key_name, data.azurerm_resource_group.rg] + type = "Microsoft.Compute/sshPublicKeys@2022-11-01" + name = random_pet.ssh_key_name.id + location = data.azurerm_resource_group.rg.location + parent_id = data.azurerm_resource_group.rg.id +} + +resource "local_sensitive_file" "ssh_private_key" { + depends_on = [random_pet.tf_resource_prefix, azapi_resource_action.ssh_public_key_gen] + content = jsondecode(azapi_resource_action.ssh_public_key_gen.output).privateKey + filename = var.ssh_key_filename != "" ? var.ssh_key_filename : "${random_pet.tf_resource_prefix.id}_id_rsa.pem" + file_permission = "0600" +} diff --git a/test/terraform_linux_vm/module_vm/dependencies/storage.tf b/test/terraform_linux_vm/module_vm/dependencies/storage.tf new file mode 100644 index 0000000..99e9cb3 --- /dev/null +++ b/test/terraform_linux_vm/module_vm/dependencies/storage.tf @@ -0,0 +1,9 @@ +# Create storage account for boot diagnostics +resource "azurerm_storage_account" "rpm_storage_account" { + depends_on = [random_id.random_id, data.azurerm_resource_group.rg] + name = "diag${random_id.random_id.hex}" + location = data.azurerm_resource_group.rg.location + resource_group_name = data.azurerm_resource_group.rg.name + account_tier = "Standard" + account_replication_type = "LRS" +} diff --git a/test/terraform_linux_vm/module_vm/dependencies/variables.tf b/test/terraform_linux_vm/module_vm/dependencies/variables.tf new file mode 100644 index 0000000..df75bf8 --- /dev/null +++ b/test/terraform_linux_vm/module_vm/dependencies/variables.tf @@ -0,0 +1,11 @@ +variable "allowed_ips" { + type = string + description = "Used to filter IP which have access to the Virtual Machine, could be a prefix, CIDR or a match like `*`" + default = "*" +} + +variable "ssh_key_filename" { + type = string + description = "Overwrite default random ssh key filename" + default = "" +} diff --git a/test/terraform_linux_vm/module_vm/install_redhat.sh b/test/terraform_linux_vm/module_vm/install_redhat.sh new file mode 100755 index 0000000..bc540fe --- /dev/null +++ b/test/terraform_linux_vm/module_vm/install_redhat.sh @@ -0,0 +1,577 @@ +#!/usr/bin/env bash +set -euo pipefail + +install_nginx(){ + sudo yum install -y nginx +} + +install_mongo(){ + local mongo_version="7.0" + echo "[mongodb-org-${mongo_version}] +name=MongoDB Repository +baseurl=https://repo.mongodb.org/yum/redhat/\$releasever/mongodb-org/${mongo_version}/\$basearch/ +gpgcheck=1 +enabled=1 +gpgkey=https://pgp.mongodb.com/server-${mongo_version}.asc" | sudo tee "/etc/yum.repos.d/mongodb-org-${mongo_version}.repo" > /dev/null + + sudo yum install -y mongodb-org + sudo systemctl start mongod +} + +install_elasticsearch(){ + echo "[elastic-8.x] +name=Elastic repository for 8.x packages +baseurl=https://artifacts.elastic.co/packages/8.x/yum +gpgcheck=0 +gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch +enabled=1 +autorefresh=1 +type=rpm-md" | sudo tee /etc/yum.repos.d/elasticsearch.repo > /dev/null + sudo yum install -y elasticsearch + sudo sed "0,/xpack.security.enabled:.*/s/xpack.security.enabled:.*/xpack.security.enabled: false/" -i /etc/elasticsearch/elasticsearch.yml + sudo systemctl daemon-reload + sudo systemctl enable elasticsearch.service + sudo systemctl start elasticsearch +} + +install_openjdk(){ + if [[ "$os" == "centos" && "$version" -lt 8 ]] + then + # @see https://www.oracle.com/java/technologies/downloads/#java17 + curl -O 'https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.rpm' + curl -O 'https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.rpm.sha256' + echo " jdk-17_linux-x64_bin.rpm" >> jdk-17_linux-x64_bin.rpm.sha256 + sha256sum -c jdk-17_linux-x64_bin.rpm.sha256 || exit 1 + + sudo yum install -y jdk-17_linux-x64_bin.rpm + else + sudo yum install -y java-17-openjdk-devel + fi + + java -version +} + +install_tools(){ + os=`cat /etc/redhat-release | awk '{ print tolower($1) }'` + version=$(awk -F'=' '/VERSION_ID/{ gsub(/"/,""); print $2}' /etc/os-release | cut -d. -f1) + echo "Detect version: $os/$version" + + if [[ "$os" == "centos" && "$version" -eq 8 ]] + then + echo "Update Centos Stream" + sudo sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* + sudo sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* + sudo yum update -y + fi + + if [[ "$version" -lt 8 ]] + then + echo "Install specific tools for RHEL < 8" + sudo yum install -y epel-release + fi + + sudo yum install -y policycoreutils-python-utils +} + +install_graviteeio_repository(){ + echo "[graviteeio] +name=graviteeio +baseurl=https://packagecloud.io/graviteeio/rpms/el/7/\$basearch +gpgcheck=0 +enabled=1 +gpgkey=https://packagecloud.io/graviteeio/rpms/gpgkey +sslverify=1 +sslcacert=/etc/pki/tls/certs/ca-bundle.crt +metadata_expire=300" | sudo tee /etc/yum.repos.d/graviteeio.repo > /dev/null + sudo yum -q makecache -y --disablerepo='*' --enablerepo='graviteeio' +} + +open_apim_ports(){ + echo "Use semanage port to open port 8084 (console) and 8085 (portal) on SE Linux." + local port_number + for port_number in 8084 8085 + do + if sudo semanage port -l | grep http_port_t | grep -q "${port_number}" + then + echo "SE Linux update right for port ${port_number}" + sudo semanage port -m -t http_port_t -p tcp "${port_number}" + else + echo "SE Linux open port ${port_number}" + sudo semanage port -a -t http_port_t -p tcp "${port_number}" + fi + done + + # @see: https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/8/html/configuring_and_managing_networking/using-and-configuring-firewalld_configuring-and-managing-networking#customizing-firewall-settings-for-a-specific-zone-to-enhance-security_working-with-firewalld-zones + if (command -v firewall-cmd > /dev/null) && ! (sudo firewall-cmd --list-ports | grep -q '8082-8085/tcp') + then + echo "firewall detected - open port range: 8082-8085/tcp" + sudo firewall-cmd --add-port=8082-8085/tcp + fi +} + +get_current_public_ip() { + local public_ip + + #case of an Azure VM + public_ip="$(curl -s -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance/network/interface?api-version=2021-02-01&format=json" | jq -r '.[].ipv4.ipAddress[].publicIpAddress')" + if echo -n "${public_ip}" | grep -q -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' + then + echo "${public_ip}" + return 0 + fi + + #case of an AWS EC2 VM + public_ip="$(curl -s "http://169.254.169.254/latest/meta-data/public-ipv4")" + if echo -n "${public_ip}" | grep -q -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' + then + echo "${public_ip}" + return 0 + fi + + #generic case + public_ip="$(curl -s 'https://ipv4.seeip.org')" + if echo -n "${public_ip}" | grep -q -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' + then + echo "${public_ip}" + return 0 + fi + + return 1 +} + +configure_frontend(){ + local public_ip="$1" + if [[ -z "${public_ip}" ]] + then + echo "Missing IP argument." >&2 + return 1 + fi + sudo sed -i "/\"baseURL\": /{s#\"baseURL\": \".*\"#\"baseURL\": \"http://${public_ip}:8083/management\"#}" /opt/graviteeio/apim/management-ui/constants.json + sudo sed -i "/\"baseURL\": /{s#\"baseURL\": \".*\"#\"baseURL\": \"http://${public_ip}:8083/portal\"#}" /opt/graviteeio/apim/portal-ui/assets/config.json + sudo sed -i "/^#portal:/c\portal:\n url: \"http://${public_ip}:8085\"" /opt/graviteeio/apim/rest-api/config/gravitee.yml + sudo sed -i "/Content-Security-Policy/{s/localhost/${public_ip}/}" /etc/nginx/conf.d/graviteeio-apim-portal-ui.conf + + # During RPM installation the management-api is started with default value. + # This mean that the portal is set in mongo DB with value 'http://localhost:4100' + # Then we have to update the configuration via management-api to update DB as the config in gravitee.yml is overwrite by DB config. + curl 'http://localhost:8083/management/organizations/DEFAULT/environments/DEFAULT/settings' \ + -u 'admin:admin' \ + --max-time 3 \ + -H 'Content-Type: application/json' \ + -X POST \ + --data-raw "{\"portal\":{\"url\":\"http://${public_ip}:8085/\"}}" +} + +install_graviteeio_from_repository(){ + local specific_version="${1}" + if [[ -n "${specific_version}" ]]; then specific_version="-${specific_version}-1"; fi + + install_graviteeio_repository + + sudo yum install -y "graviteeio-apim-4x${specific_version}" + echo "Installation of RPMs done." + + sudo systemctl daemon-reload + + echo "configure frontend" + local public_ip + if public_ip="$(get_current_public_ip)" + then + echo "Public IP detected: ${public_ip}" + configure_frontend "${public_ip}" + else + echo "Public IP not found, configure with localhost" + configure_frontend "localhost" + fi + + sudo systemctl start graviteeio-apim-gateway graviteeio-apim-rest-api + sleep 30 + wait_backends_ready + open_apim_ports + sudo systemctl restart nginx + + echo "Graviteeio installation Done." +} + +install_graviteeio_from_local_rpms(){ + local rpms_path="${1:-${HOME}}" + for rpm in "${rpms_path}"/*.rpm + do + echo "Installing ${rpm} ..." + sudo yum install -y "${rpm}" + done + echo "Installation of RPMs done." + sudo systemctl daemon-reload + sudo systemctl restart graviteeio-apim-gateway graviteeio-apim-rest-api + + wait_backends_ready + + echo "configure frontend" + local public_ip + if public_ip="$(get_current_public_ip)" + then + echo "Public IP detected: ${public_ip}" + configure_frontend "${public_ip}" + else + echo "Public IP not found, configure with localhost" + configure_frontend "localhost" + fi + + open_apim_ports + + sudo systemctl restart nginx + echo "Graviteeio installation Done." +} + +setup_license(){ + if [[ ! -f ~/license.key ]] + then + echo "~/license.key not found" >&2 + return 1 + fi + + sudo cp ~/license.key /opt/graviteeio/ + sudo chown gravitee: /opt/graviteeio/license.key + + for component in "gateway" "rest-api" + do + sudo mkdir -p "/opt/graviteeio/apim/graviteeio-apim-${component}/license" + sudo ln -s /opt/graviteeio/license.key "/opt/graviteeio/apim/graviteeio-apim-${component}/license/license.key" + sudo chown -R gravitee: "/opt/graviteeio/apim/graviteeio-apim-${component}/license" + done +} + +install_prerequities(){ + install_tools + install_openjdk + install_nginx + install_mongo + install_elasticsearch +} + +wait_backends_ready(){ + local max_iter="${1:-40}" + local expected_version="${2:-}" + + while ! test_graviteeio_backends "${expected_version}" + do + echo "Waiting 3 sec more to let backend startup... ${max_iter}" + sleep 3 + max_iter=$(( ${max_iter} -1 )) + if [[ ${max_iter} -lt 1 ]] + then + break + fi + done + + if test_graviteeio_backends "${expected_version}" + then + echo "Management API and Gateway are ready !" + else + echo "Management API and/or Gateway are in trouble..." >&2 + return 1 + fi +} + +test_graviteeio_backends(){ + local expected_version="${1:-}" + if [[ -z "${expected_version}" ]] + then + expected_version="$(ls -1 /opt/graviteeio/apim/graviteeio-apim-rest-api*/lib/gravitee-apim-rest-api-*.jar | sed 's/^.*\/gravitee-apim-rest-api-.*-\([0-9.]*\)\.jar/\1/' | sort -u | tail -n 1)" + echo "test_graviteeio on computed expected_version: ${expected_version}" + fi + + echo "Test from gravitee logs" + if ls -1 /opt/graviteeio/apim/graviteeio-apim-rest-api*/logs/gravitee.log 2> /dev/null \ + && sed -n '/Gravitee.io - Rest APIs id\[/h; ${x;p}' /opt/graviteeio/apim/graviteeio-apim-rest-api*/logs/gravitee.log | grep -q "version\[${expected_version}\]" + then + echo "Management API started successfully" + else + echo "ERROR on management api start" >&2 + return 1 + fi + + if ls -1 /opt/graviteeio/apim/graviteeio-apim-gateway*/logs/gravitee.log 2> /dev/null \ + && sed -n '/Gravitee.io - API Gateway id\[/h; ${x;p}' /opt/graviteeio/apim/graviteeio-apim-gateway*/logs/gravitee.log | grep -q "version\[${expected_version}\]" + then + echo "Gateway started successfully" + else + echo "ERROR on gateway start" >&2 + return 1 + fi +} + +test_graviteeio(){ + local expected_version="${1:-}" + if ! test_graviteeio_backends "${expected_version}" + then + return 1 + fi + + echo "Test backend gateway" + curl --user "admin:adminadmin" "http://localhost:18082/_node" + echo "" + + echo "Test backend rest-api" + curl --user 'admin:admin' "http://localhost:8083/management/organizations/DEFAULT/environments/DEFAULT/" + echo "" + + echo "Test Console UI" + curl -s 'http://localhost:8084/build.json' + echo "" + + echo "Test Portal UI" + curl -s 'http://localhost:8085/' | grep '<app-root></app-root>' + echo "" +} + +test_graviteeio_upgrade(){ + local first_version second_version + first_version="${1:-4.4.9}" + second_version="${2:-4.5.0}" + + echo "Install APIM from ${first_version}" + if [[ -d "${first_version}" ]] + then + install_graviteeio_from_local_rpms "${first_version}" + else + install_graviteeio_from_repository "${first_version}" + fi + sleep 1 + add_user + sudo systemctl restart graviteeio-apim-rest-api + sleep 20 + wait_backends_ready + sleep 3 + echo "Test backend rest-api with gravitee user" + curl --user 'gravitee:bloubiboulga' "http://localhost:8083/management/organizations/DEFAULT/environments/DEFAULT/" + echo "OK." + create_gravitee_echo_api + sleep 1 + if [[ -d "${first_version}" ]] + then + test_graviteeio + else + test_graviteeio "${first_version}" + fi + + echo "APIM ${first_version} installed - use it" + call_echo_api_x_times + echo "Wait a bit to let management api load analytics" + sleep 10 + call_apim_dashboard + call_echo_api_analytics + + echo "Upgrade APIM to ${second_version}" + if [[ -d "${second_version}" ]] + then + sudo yum upgrade -y "${second_version}"/*.rpm + else + sudo yum upgrade -y "graviteeio-apim-4x-${second_version}-1" + fi + sudo systemctl daemon-reload + sleep 1 + sudo systemctl restart graviteeio-apim-gateway graviteeio-apim-rest-api + sleep 45 + sudo systemctl restart nginx + sleep 1 + if [[ -d "${second_version}" ]] + then + test_graviteeio + else + test_graviteeio "${second_version}" + fi + + echo "APIM ${second_version} installed - use it" + call_echo_api_x_times + echo "Wait a bit to let management api load analytics" + sleep 10 + call_apim_dashboard + call_echo_api_analytics + + + echo "Test backend rest-api with gravitee user (gravitee.yml config file changes are still here)" + curl --user 'gravitee:bloubiboulga' "http://localhost:8083/management/organizations/DEFAULT/environments/DEFAULT/" + + echo "Upgrade from ${first_version} to ${second_version} done." +} + +call_echo_api_x_times(){ + local gateway_baseurl nb_iteration + gateway_baseurl="${1:-http://localhost:8082}" + nb_iteration="${2:-100}" + + for i in $(seq 1 ${nb_iteration}) + do + curl -s "${gateway_baseurl}/echo" > /dev/null + echo -n "." + done + echo "" +} + +call_echo_api_analytics(){ + local management_baseurl api_id + management_baseurl="${1:-http://localhost:8083/management}" + + api_id="$(curl -s "${management_baseurl}/v2/environments/DEFAULT/apis/_search?page=1&perPage=25" \ + -u 'admin:admin' \ + -H 'Content-Type: application/json' \ + --data-raw '{"query":"name:echo"}' | jq --raw-output '.data[0].id')" + + echo "echo api id: ${api_id}" + + echo "requests-count:" + curl "${management_baseurl}/v2/environments/DEFAULT/apis/${api_id}/analytics/requests-count" \ + -u 'admin:admin' \ + -H 'Accept: application/json, text/plain, */*' + echo "" + + echo "average-connection-duration:" + curl "${management_baseurl}/v2/environments/DEFAULT/apis/${api_id}/analytics/average-connection-duration" \ + -u 'admin:admin' \ + -H 'Accept: application/json, text/plain, */*' + echo "" + + echo "response-status-ranges:" + curl "${management_baseurl}/v2/environments/DEFAULT/apis/${api_id}/analytics/response-status-ranges" \ + -u 'admin:admin' \ + -H 'Accept: application/json, text/plain, */*' + echo "" +} + +call_apim_dashboard(){ + local management_baseurl date_from date_to analytics_params + management_baseurl="${1:-http://localhost:8083/management}" + date_from="$(date --date="now-15mins" '+%s')" + date_to="$(date --date="now" '+%s')" + + for analytics_params in "type=count&field=application" "type=group_by&field=api" "type=count&field=api" "type=group_by&field=lifecycle_state" "type=group_by&field=state" "type=group_by&field=status" "type=stats&field=response-time" + do + echo "${analytics_params}:" + curl "${management_baseurl}/organizations/DEFAULT/environments/DEFAULT/analytics?${analytics_params}&interval=2000&from=${date_from}&to=${date_to}" \ + -u 'admin:admin' \ + -H 'Accept: application/json, text/plain, */*' + echo "" + done + + echo "events:" + curl "${management_baseurl}/organizations/DEFAULT/environments/DEFAULT/platform/events?type=START_API,STOP_API,PUBLISH_API,UNPUBLISH_API&query=&api_ids=&from=${date_from}&to=${date_to}&page=0&size=5" \ + -u 'admin:admin' \ + -H 'Accept: application/json, text/plain, */*' + echo "" +} + +create_gravitee_echo_api(){ + local api_id plan_id management_baseurl + management_baseurl="${1:-http://localhost:8083/management}" + + echo "Create echo api ..." + api_id="$(curl -s "${management_baseurl}/v2/environments/DEFAULT/apis" \ + -u 'admin:admin' \ + -H 'Content-Type: application/json' \ + --data-raw '{"definitionVersion":"V4","name":"echo","apiVersion":"1.0.0","description":"The famous Gravitee echo api","listeners":[{"type":"HTTP","paths":[{"path":"/echo"}],"entrypoints":[{"type":"http-proxy","configuration":{},"qos":"AUTO"}]}],"type":"PROXY","endpointGroups":[{"name":"Default HTTP proxy group","type":"http-proxy","sharedConfiguration":{"http":{"version":"HTTP_1_1","keepAlive":true,"keepAliveTimeout":30000,"connectTimeout":3000,"pipelining":false,"readTimeout":10000,"useCompression":true,"idleTimeout":60000,"followRedirects":false,"maxConcurrentConnections":20},"proxy":{"enabled":false,"useSystemProxy":false},"ssl":{"hostnameVerifier":true,"trustAll":false,"trustStore":{"type":""},"keyStore":{"type":""}}},"endpoints":[{"name":"Default HTTP proxy","type":"http-proxy","weight":1,"inheritConfiguration":true,"configuration":{"target":"https://api.gravitee.io/echo"}}]}]}' \ + | jq --raw-output '.id')" + + sleep 0.2 + + echo "Create plan for api: ${api_id}" + plan_id="$(curl -s "${management_baseurl}/v2/environments/DEFAULT/apis/${api_id}/plans" \ + -u 'admin:admin' \ + -H 'Content-Type: application/json' \ + --data-raw '{"definitionVersion":"V4","name":"Default Keyless (UNSECURED)","description":"Default unsecured plan","mode":"STANDARD","security":{"type":"KEY_LESS","configuration":{}},"validation":"MANUAL"}' \ + | jq --raw-output '.id')" + + sleep 0.2 + + echo "Publish api (${api_id}) with plan (${plan_id})" + curl "${management_baseurl}/v2/environments/DEFAULT/apis/${api_id}/plans/${plan_id}/_publish" \ + -u 'admin:admin' \ + -H 'Content-Type: application/json' \ + --data-raw '{}' + + sleep 0.2 + + echo "Start api (${api_id})" + curl "${management_baseurl}/v2/environments/DEFAULT/apis/${api_id}/_start" \ + -u 'admin:admin' \ + -H 'Content-Type: application/json' \ + --data-raw '{}' +} + +add_user(){ + local username bcrypt_password restart + username="${1:-gravitee}" + # default password: bloubiboulga + # to generate new password: htpasswd -bnBC 10 "" bloubiboulga | tr -d ':\n' | sed 's/^$2y\$/$2a$/' + bcrypt_password="${2:-\$2a\$10\$iJmJIgf7\/Y14AtR\/lKkyzeX5cyL5nL4lgePjiBVvRkq4m652E70oy}" + restart="${3:-false}" + sudo sed -i "/^security:/,/^ *# Enable authentication/{ + /username: application1/,/#email:/{ + s/#email:/#email:\n - user:\n username: ${username}\n #firstname:\n #lastname:\n password: ${bcrypt_password}\n roles: ORGANIZATION:ADMIN,ENVIRONMENT:ADMIN\n #email:/ + } + }" /opt/graviteeio/apim/rest-api/config/gravitee.yml + + if [[ "${restart}" == "true" ]] + then + sudo systemctl restart graviteeio-apim-rest-api + wait_backends_ready + fi + + echo "User ${username} added." +} + +uninstall(){ + sudo yum remove -y graviteeio-apim-* + + if [[ "${1:-}" == "--hard" && -d /opt/graviteeio ]] + then + echo "Delete folder /opt/graviteeio" + sudo rm -rf /opt/graviteeio + fi +} + +help(){ + cat <<EOF +This script let you install GraviteeIO from local RPM or official published repo + +usage : $0 [COMMAND] + +COMMAND : (default: install_prerequities) +${COMMANDS} + +exemple : +./install_redhat.sh install_prerequities + +./install_redhat.sh install_graviteeio_from_repository +./install_redhat.sh install_graviteeio_from_repository 4.2.6 + +./install_redhat.sh install_graviteeio_from_local_rpms +./install_redhat.sh install_graviteeio_from_local_rpms /path/to/rpms/folder + +./install_redhat.sh test_graviteeio + +./install_redhat.sh create_gravitee_echo_api +curl -s -H "say: gloubiboulga" "http://localhost:8082/echo" | jq '.' + +./install_redhat.sh test_graviteeio_upgrade +./install_redhat.sh test_graviteeio_upgrade "4.4.9" "4.5.0" +./install_redhat.sh test_graviteeio_upgrade "4.4.9" "/home/azureadmin/rpms" + +./install_redhat.sh uninstall + +EOF +} + +### Default context ### +COMMANDS="$(sed -n '/^[a-z].*(){$/ s/(){//p' $0)" +COMMAND="install_prerequities" + +### Parse args ### +if [[ -n "${1:-}" ]] +then + COMMAND="$1" + shift +fi + +### main ### +${COMMAND} $@ diff --git a/test/terraform_linux_vm/module_vm/install_suze.sh b/test/terraform_linux_vm/module_vm/install_suze.sh new file mode 100644 index 0000000..450f614 --- /dev/null +++ b/test/terraform_linux_vm/module_vm/install_suze.sh @@ -0,0 +1,142 @@ +#!/bin/bash + +install_nginx() { + sudo zypper addrepo -G -t yum -c 'http://nginx.org/packages/sles/15' nginx + sudo rpm --import http://nginx.org/keys/nginx_signing.key + sudo zypper -n install nginx +} + +install_mongo() { + sudo rpm --import https://www.mongodb.org/static/pgp/server-6.0.asc + + version=$(cut -d "=" -f2 <<< `cat /etc/os-release | grep VERSION_ID` | tr -d '"') + if [[ $version = 12* ]]; then + sudo zypper addrepo --gpgcheck "https://repo.mongodb.org/zypper/suse/12/mongodb-org/6.0/x86_64/" mongodb + else + sudo zypper addrepo --gpgcheck "https://repo.mongodb.org/zypper/suse/15/mongodb-org/6.0/x86_64/" mongodb + fi + + sudo zypper -n install mongodb-org + sudo systemctl start mongod +} + +install_elasticsearch() { + sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch + echo "[elasticsearch] +name=Elasticsearch repository for 8.x packages +baseurl=https://artifacts.elastic.co/packages/8.x/yum +gpgcheck=1 +gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch +enabled=1 +autorefresh=1 +type=rpm-md" | sudo tee /etc/zypp/repos.d/elasticsearch.repo > /dev/null + sudo zypper modifyrepo --enable elasticsearch + sudo zypper -n install elasticsearch + sudo zypper modifyrepo --disable elasticsearch + sudo sed "0,/xpack.security.enabled:.*/s/xpack.security.enabled:.*/xpack.security.enabled: false/" -i /etc/elasticsearch/elasticsearch.yml + sudo systemctl start elasticsearch +} + +install_openjdk() { + version=$(cut -d "=" -f2 <<< `cat /etc/os-release | grep VERSION_ID` | tr -d '"') + if [[ $version = 12* ]]; then + sudo zypper addrepo https://download.opensuse.org/repositories/Java:Factory/SLE_12_SP5/Java:Factory.repo + sudo zypper --gpg-auto-import-keys ref + sudo zypper refresh + fi + + sudo zypper -n install java-17-openjdk +} + +install_prerequities() { + install_openjdk + install_nginx + install_mongo + install_elasticsearch +} + +install_graviteeio_repository() { + echo "[graviteeio] + name=graviteeio + baseurl=https://packagecloud.io/graviteeio/rpms/el/7/\$basearch + gpgcheck=0 + enabled=1 + gpgkey=https://packagecloud.io/graviteeio/rpms/gpgkey + sslverify=1 + sslcacert=/etc/pki/tls/certs/ca-bundle.crt + metadata_expire=300 + type=rpm-md" | sudo tee /etc/zypp/repos.d/graviteeio.repo > /dev/null +} + +install_graviteeio_from_repository() { + install_graviteeio_repository + + sudo zypper -n install graviteeio-apim-4x + + sudo systemctl daemon-reload + sudo systemctl start graviteeio-apim-gateway graviteeio-apim-rest-api + http_response=$(curl -w "%{http_code}" -o /tmp/curl_body "http://169.254.169.254/latest/meta-data/public-ipv4") + if [ $http_response == "200" ]; then + sudo sed -i -e "s/localhost/$(cat /tmp/curl_body)/g" /opt/graviteeio/apim/management-ui/constants.json + sudo sed -i -e "s;/portal;http://$(cat /tmp/curl_body):8083/portal;g" /opt/graviteeio/apim/portal-ui/assets/config.json + fi + sudo systemctl restart nginx + echo "Graviteeio installation Done." +} + +install_graviteeio_from_local_rpms() { + for rpm in ~/*.rpm + do + echo "Installing ${rpm} ..." + sudo zypper --non-interactive --no-gpg-checks install "${rpm}" + done + echo "Installation of RPMs done." + + sudo systemctl daemon-reload + sudo systemctl start graviteeio-apim-gateway graviteeio-apim-rest-api + + echo "wait backend start" + sleep 45 #wait backend start + + echo "run frontend" + http_response=$(curl -w "%{http_code}" -o /tmp/curl_body "http://169.254.169.254/latest/meta-data/public-ipv4") + if [ $http_response == "200" ]; then + sudo sed -i -e "s/localhost/$(cat /tmp/curl_body)/g" /opt/graviteeio/apim/management-ui/constants.json + sudo sed -i -e "s;/portal;http://$(cat /tmp/curl_body):8083/portal;g" /opt/graviteeio/apim/portal-ui/assets/config.json + fi + + sudo systemctl restart nginx + echo "Graviteeio installation Done." +} + +help() { + cat <<EOF +This script let you install GraviteeIO from local RPM or official published repo + +usage : $0 [COMMAND] + +COMMAND : (default: install_prerequities) +${COMMANDS} + +exemple : +./install_redhat_graviteeio.sh install_prerequities + +./install_redhat_graviteeio.sh install_graviteeio_from_repository + +./install_redhat_graviteeio.sh install_graviteeio_from_local_rpms + +EOF +} + +### Default context ### +COMMANDS="$(sed -n '/^[a-z].*(){$/ s/(){//p' $0)" +COMMAND="install_prerequities" + +### Parse args ### +if [[ -n "$1" ]] +then + COMMAND="$1" +fi + +### main ### +${COMMAND} diff --git a/test/terraform_linux_vm/module_vm/main.tf b/test/terraform_linux_vm/module_vm/main.tf new file mode 100644 index 0000000..3a985ba --- /dev/null +++ b/test/terraform_linux_vm/module_vm/main.tf @@ -0,0 +1,82 @@ +module "dependencies" { + source = "./dependencies" + allowed_ips = var.allowed_ips + ssh_key_filename = var.ssh_key_filename +} + +# Agreement of OS offer +#resource "azurerm_marketplace_agreement" "this" { +# publisher = "redhat" +# offer = "rh-rhel" +# plan = "rh-rhel9" +#} + +# Create virtual machine +resource "azurerm_linux_virtual_machine" "rpm_vm" { + depends_on = [module.dependencies] + name = "${module.dependencies.random_pet-tf_resource_prefix-id}_VM" + location = module.dependencies.azurerm_resource_group-rg-location + resource_group_name = module.dependencies.azurerm_resource_group-rg-name + network_interface_ids = [module.dependencies.azurerm_network_interface-rpm_tf_nic-id] + size = var.vm_size + + os_disk { + name = "${module.dependencies.random_pet-tf_resource_prefix-id}_OsDisk" + caching = "ReadWrite" + storage_account_type = "Premium_LRS" + } + + # plan { + # name = "rh-rhel9" + # product = "rh-rhel" + # publisher = "RedHat" + # } + + source_image_reference { + publisher = var.os_publisher + offer = var.os_offer + sku = var.os_sku + version = var.os_version + } + + computer_name = replace(module.dependencies.random_pet-tf_resource_prefix-id, "_", "") + admin_username = var.username + + admin_ssh_key { + username = var.username + public_key = jsondecode(module.dependencies.azapi_resource_action-ssh_public_key_gen-output).publicKey + } + + boot_diagnostics { + storage_account_uri = module.dependencies.azurerm_storage_account-rpm_storage_account-primary_blob_endpoint + } + + connection { + type = "ssh" + user = var.username + private_key = jsondecode(module.dependencies.azapi_resource_action-ssh_public_key_gen-output).privateKey + host = self.public_ip_address + } + + provisioner "file" { + source = "${path.module}/install_redhat.sh" + destination = "install_redhat.sh" + } + + provisioner "file" { + source = "${path.module}/install_suze.sh" + destination = "install_suze.sh" + } + + # Hack mode on: + # It is not possible in terraform to have conditional on provisioner + # So if the local_rpm_folder_path variable is not set, we re-upload the install_redhat.sh script ... + provisioner "file" { + source = var.local_rpm_folder_path != null && var.local_rpm_folder_path != "" ? var.local_rpm_folder_path : "${path.module}/install_redhat.sh" + destination = var.local_rpm_folder_path != null && var.local_rpm_folder_path != "" ? "rpms" : "install_redhat.sh" + } + + provisioner "remote-exec" { + inline = var.remote_exec_cmds + } +} diff --git a/test/terraform_linux_vm/module_vm/outputs.tf b/test/terraform_linux_vm/module_vm/outputs.tf new file mode 100644 index 0000000..7396c5a --- /dev/null +++ b/test/terraform_linux_vm/module_vm/outputs.tf @@ -0,0 +1,11 @@ +output "public_ip_address" { + value = azurerm_linux_virtual_machine.rpm_vm.public_ip_address +} + +output "ssh_command_to_connect" { + value = "ssh -i ${module.dependencies.local_sensitive_file-ssh_private_key-filename} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \\\n\t -L 18082:localhost:18082 -L 8082:localhost:8082 -L 8083:localhost:8083 -L 8084:localhost:8084 -L 8085:localhost:8085 \\\n\t ${var.username}@${azurerm_linux_virtual_machine.rpm_vm.public_ip_address}" +} + +output "scp_command_to_push_rpm" { + value = "scp -i ${module.dependencies.local_sensitive_file-ssh_private_key-filename} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \\\n\t ../../../apim/4.x/graviteeio-apim-*-4x*.rpm ${var.username}@${azurerm_linux_virtual_machine.rpm_vm.public_ip_address}:." +} diff --git a/test/terraform_linux_vm/module_vm/providers.tf b/test/terraform_linux_vm/module_vm/providers.tf new file mode 100644 index 0000000..15e1f30 --- /dev/null +++ b/test/terraform_linux_vm/module_vm/providers.tf @@ -0,0 +1,15 @@ +terraform { + required_version = ">=1.7" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~>3.94" + } + } +} + +provider "azurerm" { + features {} + subscription_id = "02ae5fba-84b0-443a-9df6-9be92297c139" // Gravitee-SaaS +} diff --git a/test/terraform_linux_vm/module_vm/variables.tf b/test/terraform_linux_vm/module_vm/variables.tf new file mode 100644 index 0000000..5525d0b --- /dev/null +++ b/test/terraform_linux_vm/module_vm/variables.tf @@ -0,0 +1,57 @@ +variable "allowed_ips" { + type = string + description = "Used to filter IP which have access to the Virtual Machine, could be a prefix, CIDR or a match like `*`" + default = "*" +} + +variable "ssh_key_filename" { + type = string + description = "Overwrite default random ssh key filename" + default = "" +} + +variable "username" { + type = string + description = "The username for the local account that will be created on the new VM." + default = "azureadmin" +} + +variable "vm_size" { + type = string + description = "VM size [Standard_DS1_v2,Standard_DS2_v3,Standard_D2ads_v5]" + default = "Standard_D2ads_v5" +} +variable "os_publisher" { + type = string + description = "Operating System Publisher [RedHat,SUSE]" + default = "RedHat" +} +variable "os_offer" { + type = string + description = "Operating System Offer [RHEL,sles]" + default = "RHEL" +} +variable "os_sku" { + type = string + description = "Operating System SKU [93-gen2,15-sp3]" + default = "93-gen2" +} +variable "os_version" { + type = string + description = "Operating System Version [latest,9.3.2024022812]" + default = "latest" +} + +variable "remote_exec_cmds" { + type = list(string) + description = "list of command to run when ready via SSH connexion" + default = [ + "cat /etc/*release*" + ] +} + +variable "local_rpm_folder_path" { + type = string + description = "Path to the local folder where rpm are stored, like: '../../../apim/4.x/'" + default = "" +} diff --git a/test/terraform_linux_vm/readme.adoc b/test/terraform_linux_vm/readme.adoc new file mode 100644 index 0000000..4dcbd44 --- /dev/null +++ b/test/terraform_linux_vm/readme.adoc @@ -0,0 +1,285 @@ += Create Azure VM via terraform to test RPMs + +Here are some terraform code to let you: + + +* create a VM with OS: +** RedHat 8/9 +** Centos Stream 9 +** Centos 7 +** Suze +* make it accessible only from our IP on SSH port (22) +* ephemeral SSH key is generated +* with included script to make multiple installation easier: +** install all gravitee prerequisites (java, mongo, elastic) +** install all gravitee from artifact hub repo with specific version +** install all gravitee from built RPMs +** configure everything to make it works by default from SSH tunnel + + +== Prerequisites + +* Get an access to Azure Resource https://portal.azure.com/#@graviteesource.com/resource/subscriptions/02ae5fba-84b0-443a-9df6-9be92297c139/resourceGroups/gravitee-rpm-dev/overview[gravitee-rpm-dev] +* Having https://developer.hashicorp.com/terraform/install[terraform] installed on your laptop (`asdf install terraform latest` for `asdf` users 😁) +* Check existing resource allocated: https://portal.azure.com/#@graviteesource.com/resource/subscriptions/02ae5fba-84b0-443a-9df6-9be92297c139/resourceGroups/gravitee-rpm-dev/overview + + +== Search VM + +The best way to found valid info about which VM to create is to create it manually and on VM overview and "Essential" pane, click on the right to "JSON view" and get your info in field: "imageReference". + +[source,bash] +---- +az vm image list --all \ + --subscription="02ae5fba-84b0-443a-9df6-9be92297c139" \ + --location="francecentral" \ + --publisher="redhat" \ + --architecture="x64" \ + --offer="rh-rhel" \ + --sku="9" \ + --output=table \ + | grep -v -e "redhat-limited" -e "gen1" | vim - + +az vm image show \ + --subscription="02ae5fba-84b0-443a-9df6-9be92297c139" \ + --location="francecentral" \ + --urn "RedHat:rh-rhel:rh-rhel9:9.3.2024020814" \ + | vim - + +az vm list-sizes \ + --subscription="02ae5fba-84b0-443a-9df6-9be92297c139" \ + --location="francecentral" \ + --output=table \ + | vim - +---- + +Note: "northeurope" has smaller price but current ressource_group is on "francecentral" which is maybe more green. + + +== Provision a VM quickly + +[source,bash] +---- +cd redhat +terraform init -upgrade +export TF_VAR_allowed_ips="$(curl -s 'https://ipv4.seeip.org')/32" +terraform apply -auto-approve + +ssh ... +tmux attach +... + +terraform destroy -auto-approve +rm -rf .terraform* terraform.tfstate* +---- + + + +== Provision a VM in details + +. From `redhat`, `suze` or `centos` folder: ++ +[source,bash] +---- +cd redhat +---- + +. Initialise terraform ++ +[source,bash] +---- +terraform init -upgrade + +export TF_VAR_allowed_ips="$(curl -s 'https://ipv4.seeip.org')/32" +---- +Note: the `allowed_ips` var is used to filter which IP is able to connect to the VM. +By default, it is public. + +. Other customization ++ +[source,bash] +---- +export TF_VAR_username="matthieu" +export TF_VAR_allowed_ips="$(curl -s 'https://ipv4.seeip.org')/32" +export TF_VAR_ssh_key_filename="sshkey.pem" +export TF_VAR_local_rpm_folder_path="${HOME}/development/workspaces/gravitee-io/packages/apim/4.x/rpms" +export TF_VAR_remote_exec_cmds="[\"sudo yum install -y tmux\", \"chmod u+x install_*.sh\", \"tmux new-session \\\; send-keys './install_redhat.sh && sleep 60 && ./install_redhat.sh test_graviteeio_upgrade 4.4.9 /home/matthieu/rpms' C-m \\\; detach-client\"]" +env | grep TF_VAR +---- + +. plan and apply to get your VM ++ +[source,bash] +---- +terraform plan -out main.tfplan +terraform apply main.tfplan +---- + +. The ssh command to connect to the VM is provided as a terraform output in `ssh_command_to_connect` var. + +. In case you want to test local RPMs +.. build your RPM ++ +[source,bash] +---- +cd ../../../apim/4.x/ +./build.sh -v 4.2.4 +cd - +---- + +.. To upload local rpm builded to the remote VM (after already build RPMs): ++ +[source,bash] +---- +scp -i rpm_*_id_rsa.pem ../../apim/4.x/graviteeio-apim-*-4x*.rpm azureadmin@20.188.42.181:. +---- + +. And then in the remote machine (after ssh connexion): ++ +[source,bash] +---- +tmux attach +./install_redhat.sh help +---- + +. Test that APIM is running: ++ +[source,bash] +---- +curl 'http://localhost:8084/' |grep -i gravitee +curl 'http://localhost:8085/' |grep -i gravitee +---- + +. Notice that current script `install_redhat.sh` have some usefull command like: ++ +[source,bash] +---- +./install_redhat.sh test_graviteeio_upgrade 4.4.9 /home/matthieu/rpms +---- +Which install from repository the version 4.4.9 and after creating api and tested it, upgrade with local rpm installation and test that all work. + +. And then destroy the VM when test is ended ++ +[source,bash] +---- +terraform plan -destroy -out main.destroy.tfplan +terraform apply -auto-approve main.destroy.tfplan +---- + +. cleanup terraform data: ++ +WARNING: remove these files/folders only after deletion of azure resources ++ +[source,bash] +---- +rm -rf .terraform* terraform.tfstate* +---- + + + +=== Additionnal notes + +* To see generated plan later: ++ +[source,bash] +---- +terraform show -no-color main.tfplan | vim - +---- +Notice that you can remove the `-no-color` param and use plugin `AnsiEsc` in vim to get color rendering. + +* Test VM exist in Azure: ++ +[source,bash] +---- +az vm list \ + --subscription="02ae5fba-84b0-443a-9df6-9be92297c139" \ + --resource-group "gravitee-rpm-dev" \ + --query "[].{\"VM Name\":name}" \ + --output table +---- + + + +== External Documentation + +* Based on documentation: https://learn.microsoft.com/fr-fr/azure/virtual-machines/linux/quick-create-terraform[Quick create terraform] +* https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs[Terraform Azure provider] + +Some documentation about redhat on Azure and Plan (needed for Centos VMs): + +* https://learn.microsoft.com/en-us/azure/virtual-machines/workloads/redhat/redhat-images#rhel-9-image-types +* https://learn.microsoft.com/en-us/partner-center/marketplace/marketplace-virtual-machines +* https://learn.microsoft.com/en-us/partner-center/marketplace/azure-vm-plan-pricing-and-availability + + + +== Internal Documentation + +This terraform code allow us to easily create ephemeral VM to test RPM, configuration, anything. + +Organisation: + +* `module_vm`: this module centralize all needed to provision a VM +** `module_vm/dependencies`: this module is a submodule use for the case where we want a specific VM definition but still reuse everything else (networks, etc) +* `redhat`: this is the terraform input code to provision a RedHat VM, by default in version 9 +* `suze`: same but for Suze 15 +* `centos`: same with a specific VM (we need a plan and a marketplace agreement) with Centos Stream 9 + + +=== VM specificities + +==== Centos Stream 9 + +This VM need a plan and marketplace agreement as it was provided by an external Partner in Azure Marketplace. + +==== Centos 7 + +This VM need a plan and marketplace agreement as it was provided by an external Partner in Azure Marketplace. + +to use centos 7, define env var: + +[source,bash] +---- +export TF_VAR_os_name="centos-7-minimal" +---- + + +==== RedHat 8 + +To provision a VM with RedHat 8 you can set: + +[source,bash] +---- +export TF_VAR_os_sku=8-gen2 +export TF_VAR_remote_exec_cmds='["cat /etc/*release*"]' +---- + +However, by default you can't update repolist and install any software. You need to register to RedHat first in: +https://www.redhat.com/wapps/ugc/register.html + +And then you can connect to the VM and run: + +[source,bash] +---- +# Red Hat Subscription Management credentials +RHSM_USERNAME="YOUR_USERNAME" +RHSM_PASSWORD="YOUR_PASSWORD" + +# Activate the Red Hat subscription +subscription-manager register --username="$RHSM_USERNAME" --password="$RHSM_PASSWORD" --auto-attach + +# Refresh subscription manager +subscription-manager refresh + +# List available subscriptions +subscription-manager list --available +---- + +Plus continue the installation process. + + +== TODOs + +* refactor install_* script to `install.sh` and `manage.sh` dedicated to test +* use `set -euo pipefail` in sh script +* test all changes on suze and centos \ No newline at end of file diff --git a/test/terraform_linux_vm/redhat/main.tf b/test/terraform_linux_vm/redhat/main.tf new file mode 100644 index 0000000..748325d --- /dev/null +++ b/test/terraform_linux_vm/redhat/main.tf @@ -0,0 +1,66 @@ +variable "allowed_ips" { + type = string + description = "Used to filter IP which have access to the Virtual Machine, could be a prefix, CIDR or a match like `*`" + default = "*" +} + +variable "ssh_key_filename" { + type = string + description = "Overwrite default random ssh key filename" + default = "" +} + +variable "username" { + type = string + description = "The username for the local account that will be created on the new VM." + default = "azureadmin" +} + +variable "os_sku" { + type = string + description = "Operating System SKU [93-gen2,8-gen2,7.6,6.9]" + default = "93-gen2" +} + +variable "remote_exec_cmds" { + type = list(string) + description = "list of command to run when ready via SSH connexion" + default = [ + "sudo yum install -y tmux", + "chmod u+x install_*.sh", + "tmux new-session \\; send-keys './install_redhat.sh' C-m \\; detach-client" + ] +} + +variable "local_rpm_folder_path" { + type = string + description = "Path to the local folder where rpm are stored, like: '../../../apim/4.x/'" + default = "" +} + +module "redhat-vm" { + source = "../module_vm" + username = var.username + allowed_ips = var.allowed_ips + ssh_key_filename = var.ssh_key_filename + local_rpm_folder_path = var.local_rpm_folder_path + + vm_size = "Standard_D2ads_v5" + os_publisher = "RedHat" + os_offer = "RHEL" + os_sku = var.os_sku + os_version = "latest" + remote_exec_cmds = var.remote_exec_cmds +} + +output "public_ip_address" { + value = module.redhat-vm.public_ip_address +} + +output "ssh_command_to_connect" { + value = module.redhat-vm.ssh_command_to_connect +} + +output "scp_command_to_push_rpm" { + value = module.redhat-vm.scp_command_to_push_rpm +} diff --git a/test/terraform_linux_vm/suze/main.tf b/test/terraform_linux_vm/suze/main.tf new file mode 100644 index 0000000..8288164 --- /dev/null +++ b/test/terraform_linux_vm/suze/main.tf @@ -0,0 +1,42 @@ +variable "allowed_ips" { + type = string + description = "Used to filter IP which have access to the Virtual Machine, could be a prefix, CIDR or a match like `*`" + default = "*" +} + +variable "username" { + type = string + description = "The username for the local account that will be created on the new VM." + default = "azureadmin" +} + +module "suze-vm" { + source = "../module_vm" + username = var.username + allowed_ips = var.allowed_ips + + vm_size = "Standard_D2ads_v5" + os_publisher = "suse" + os_offer = "sles-15-sp5-basic" + os_sku = "gen2" + os_version = "latest" // 2024.02.07 + remote_exec_cmds = [ + "sleep 45", // wait a bit to let the system start, if not, SUSEConnect will failed + "sudo SUSEConnect --product PackageHub/15.5/x86_64 --auto-agree-with-licenses", + "sudo zypper --non-interactive in tmux", + "chmod u+x *.sh", + "tmux new-session \\; send-keys './install_suze.sh install_prerequities' C-m \\; detach-client" + ] +} + +output "public_ip_address" { + value = module.suze-vm.public_ip_address +} + +output "ssh_command_to_connect" { + value = module.suze-vm.ssh_command_to_connect +} + +output "scp_command_to_push_rpm" { + value = module.suze-vm.scp_command_to_push_rpm +}