├── simple_http_lb_with_prom_grafana ├── img │ ├── dashboard.png │ └── architecture.png ├── outputs.tf ├── cert.tf ├── grafana.tf ├── network.tf ├── variables.tf ├── providers.tf ├── instances.tf ├── loadbalancer.tf └── README.md ├── private_network ├── README.md └── private_network.tf ├── .gitignore ├── s3_policy ├── README.md └── s3_policy.tf ├── simple_http_lb ├── README.md └── simple_http_lb.tf ├── s3_bucket_only ├── README.md └── s3_bucket_only.tf ├── README.md └── LICENSE /simple_http_lb_with_prom_grafana/img/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yomovh/tf-at-ovhcloud/HEAD/simple_http_lb_with_prom_grafana/img/dashboard.png -------------------------------------------------------------------------------- /simple_http_lb_with_prom_grafana/img/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yomovh/tf-at-ovhcloud/HEAD/simple_http_lb_with_prom_grafana/img/architecture.png -------------------------------------------------------------------------------- /private_network/README.md: -------------------------------------------------------------------------------- 1 | # Pre requisites 2 | - same as the one described in the root [README.md](../README.md) 3 | - a vrack has been created in the control panel. You can create up to 4.000 VLANs inside a vrack. The vrack id will be requested when `terraform apply` 4 | 5 | # Example description 6 | This example creates: 7 | - one openstack user to be able to manage the network 8 | - a link between the vrack and the public cloud project 9 | - a private network with the specified VLAN ID 10 | - a subnet inside that network -------------------------------------------------------------------------------- /simple_http_lb_with_prom_grafana/outputs.tf: -------------------------------------------------------------------------------- 1 | ######################################################################################## 2 | # Outputs 3 | ######################################################################################## 4 | output "lb_url" { 5 | value = "https://${var.dns_subdomain}.${var.dns_zone}" 6 | description = "The loadbalancer public url" 7 | } 8 | 9 | 10 | output "grafana_url" { 11 | value = "https://${var.dns_subdomain}.${var.dns_zone}:${openstack_lb_listener_v2.graf_listener.protocol_port}/dashboards" 12 | description = "Grafana url" 13 | 14 | } 15 | output "grafana_user" { 16 | value = ovh_cloud_project_database_user.avnadmin.name 17 | } 18 | 19 | output "grafana_password" { 20 | value = ovh_cloud_project_database_user.avnadmin.password 21 | sensitive = true 22 | } 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # .tfstate files 5 | *.tfstate 6 | *.tfstate.* 7 | 8 | # terraform lock file 9 | .terraform.lock.hcl 10 | 11 | # Crash log files 12 | crash.log 13 | 14 | # Ignore any .tfvars files that are generated automatically for each Terraform run. Most 15 | # .tfvars files are managed as part of configuration and so should be included in 16 | # version control. 17 | # 18 | *.tfvars 19 | 20 | 21 | # Ignore override files as they are usually used to override resources locally and so 22 | # are not checked in 23 | override.tf 24 | override.tf.json 25 | *_override.tf 26 | *_override.tf.json 27 | 28 | # Include override files you do wish to add to version control using negated pattern 29 | # 30 | # !example_override.tf 31 | 32 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 33 | # example: *tfplan* 34 | -------------------------------------------------------------------------------- /simple_http_lb_with_prom_grafana/cert.tf: -------------------------------------------------------------------------------- 1 | resource "tls_private_key" "private_key" { 2 | algorithm = "RSA" 3 | } 4 | resource "acme_registration" "reg" { 5 | account_key_pem = tls_private_key.private_key.private_key_pem 6 | email_address = var.acme_email_address 7 | } 8 | 9 | resource "acme_certificate" "cert" { 10 | account_key_pem = acme_registration.reg.account_key_pem 11 | common_name = "${var.dns_subdomain}.${var.dns_zone}" 12 | disable_complete_propagation = var.acme_disable_complete_propagation 13 | 14 | dns_challenge { 15 | provider = "ovh" 16 | } 17 | } 18 | 19 | resource "openstack_keymanager_secret_v1" "tls_secret" { 20 | name = "${var.resource_prefix}tls_secret" 21 | payload_content_type = "application/octet-stream" 22 | payload_content_encoding = "base64" 23 | payload = acme_certificate.cert.certificate_p12 24 | } 25 | -------------------------------------------------------------------------------- /s3_policy/README.md: -------------------------------------------------------------------------------- 1 | # Additional environment variables for S3 use cases 2 | **If you have AWS CLI already configured, you are good to go !** 3 | 4 | Else, due to a limitation in Terraform dependency graph for providers initialization (see this long lasting [issue](https://github.com/hashicorp/terraform/issues/2430)) it is required to have the following environement variables defined (even if they are dummy one and overridden during the script execution) : `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` 5 | 6 | If they are not already defined you can use the following: 7 | 8 | ```bash 9 | export AWS_ACCESS_KEY_ID="no_need_to_define_an_access_key" 10 | export AWS_SECRET_ACCESS_KEY="no_need_to_define_a_secret_key" 11 | ``` 12 | 13 | # Example description 14 | This example creates : 15 | - 3 "Object store Operator" users 16 | - A bucket 17 | - A text file and uploads it into the bucket 18 | - A read only policy and associates it with one user 19 | - A read write policy and associates it with one user -------------------------------------------------------------------------------- /simple_http_lb/README.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | **This simple HTTP load balancer does not use HTTPS which is standard nowadays. This choice was made to simplify this sample. If you need an HTTPS, please open an issue** 4 | 5 | This example creates: 6 | - an openstack user that will be used to create the whole infrastructure 7 | - a private network 8 | - a Floating IP and a virtual router (that is used a Public Gateway to manage egress & ingress from / to the private network) 9 | - an HTTP load balancer 10 | - 2 HTTP servers (the number of HTTP server can changed using the `instance_nb` variable) 11 | - optionally if a `stream_id` is set, the [log_subscription](https://registry.terraform.io/providers/ovh/ovh/latest/docs/resources/cloud_project_region_loadbalancer_log_subscription) is created so that you can see your HTTP logs in your Log Data Platform instance ! 12 | 13 | The output of the `terraform apply` will provide the public ip of your load balancer. Open it in a browser and hit reload to see the round robin in action ! 14 | -------------------------------------------------------------------------------- /s3_bucket_only/README.md: -------------------------------------------------------------------------------- 1 | # Additional environment variables for S3 use cases 2 | **If you have AWS CLI already configured, you are good to go !** 3 | 4 | Else, due to a limitation in Terraform dependency graph for providers initialization (see this long lasting [issue](https://github.com/hashicorp/terraform/issues/2430)) it is required to have the following environement variables defined (even if they are dummy one and overridden during the script execution) : `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` 5 | 6 | If they are not already defined you can use the following: 7 | 8 | ```bash 9 | export AWS_ACCESS_KEY_ID="no_need_to_define_an_access_key" 10 | export AWS_SECRET_ACCESS_KEY="no_need_to_define_a_secret_key" 11 | ``` 12 | 13 | # Example description 14 | This example creates an S3 user to be able to have access & secret key to configure Hashicorp AWS provider. 15 | Then it creates a bucket. 16 | 17 | # Update region / storage class 18 | This [page](https://help.ovhcloud.com/csm/en-ie-public-cloud-storage-s3-location?id=kb_article_view&sysparm_article=KB0047393) provides an up to date lists of regions and endpoints for S3 object storage. 19 | 20 | According to your choice, update the `region` and `s3_endpoint` variables. -------------------------------------------------------------------------------- /simple_http_lb_with_prom_grafana/grafana.tf: -------------------------------------------------------------------------------- 1 | ######################################################################################## 2 | # Grafana 3 | ######################################################################################## 4 | resource "ovh_cloud_project_database" "grafana" { 5 | service_name = var.ovh_public_cloud_project_id 6 | description = "${var.resource_prefix}grafana" 7 | engine = "grafana" 8 | version = "10.0" 9 | plan = "essential" 10 | 11 | flavor = "db1-4" 12 | nodes { 13 | region = substr(var.openstack_region, 0, 3) 14 | network_id = openstack_networking_network_v2.tf_lb_network.id 15 | subnet_id = openstack_networking_subnet_v2.tf_lb_subnet.id 16 | } 17 | ip_restrictions { 18 | description = "private network subnet" 19 | ip = openstack_networking_subnet_v2.tf_lb_subnet.cidr 20 | } 21 | } 22 | 23 | data "dns_a_record_set" "grafana" { 24 | host = ovh_cloud_project_database.grafana.endpoints[0].domain 25 | depends_on = [ 26 | ovh_cloud_project_database.grafana 27 | ] 28 | } 29 | 30 | resource "grafana_data_source" "prometheus" { 31 | type = "prometheus" 32 | name = "prom" 33 | url = "http://${openstack_compute_instance_v2.prometheus.access_ip_v4}:9090" 34 | } 35 | 36 | resource "grafana_dashboard" "octavia_dashboard" { 37 | config_json = file("resources/octavia-amphora-load-balancer_rev2.json") 38 | } 39 | 40 | resource "ovh_cloud_project_database_user" "avnadmin" { 41 | service_name = var.ovh_public_cloud_project_id 42 | engine = ovh_cloud_project_database.grafana.engine 43 | cluster_id = ovh_cloud_project_database.grafana.id 44 | name = "avnadmin" 45 | } 46 | 47 | -------------------------------------------------------------------------------- /simple_http_lb_with_prom_grafana/network.tf: -------------------------------------------------------------------------------- 1 | ######################################################################################## 2 | # Network 3 | ######################################################################################## 4 | data "openstack_networking_network_v2" "ext_net" { 5 | name = var.external_network 6 | external = true 7 | depends_on = [ 8 | ovh_cloud_project_user.user 9 | ] 10 | } 11 | 12 | resource "openstack_networking_network_v2" "tf_lb_network" { 13 | name = "${var.resource_prefix}network" 14 | admin_state_up = "true" 15 | } 16 | 17 | 18 | resource "openstack_networking_subnet_v2" "tf_lb_subnet" { 19 | name = "${var.resource_prefix}subnet" 20 | network_id = openstack_networking_network_v2.tf_lb_network.id 21 | cidr = "10.0.0.0/24" 22 | gateway_ip = "10.0.0.254" 23 | dns_nameservers = ["213.186.33.99"] 24 | ip_version = 4 25 | 26 | } 27 | 28 | resource "openstack_networking_router_v2" "tf_lb_router" { 29 | name = "${var.resource_prefix}router" 30 | external_network_id = data.openstack_networking_network_v2.ext_net.id 31 | } 32 | 33 | resource "openstack_networking_floatingip_v2" "tf_lb_floatingip" { 34 | pool = data.openstack_networking_network_v2.ext_net.name 35 | } 36 | 37 | resource "openstack_networking_router_interface_v2" "tf_lb_router_itf_priv" { 38 | router_id = openstack_networking_router_v2.tf_lb_router.id 39 | subnet_id = openstack_networking_subnet_v2.tf_lb_subnet.id 40 | } 41 | 42 | resource "openstack_networking_floatingip_associate_v2" "association" { 43 | floating_ip = openstack_networking_floatingip_v2.tf_lb_floatingip.address 44 | port_id = openstack_lb_loadbalancer_v2.tf_lb.vip_port_id 45 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Terraform at OVHcloud 2 | This repository contains my unitary examples of terraform resources with multiples providers : OVH, Openstack and Hashicorp AWS to automate OVHcloud resource provisionning. 3 | 4 | I tried to diminish the number of pre requisites by creating the Openstack / S3 users from within the terraform scripts. 5 | 6 | ## Pre requisites 7 | 8 | The following environment variables need to be defined for the OVH provider : 9 | * OVH_ENDPOINT 10 | * OVH_APPLICATION_KEY 11 | * OVH_APPLICATION_SECRET 12 | * OVH_CONSUMER_KEY 13 | 14 | The following env variable is required specifically for those scripts : 15 | * TF_VAR_OVH_PUBLIC_CLOUD_PROJECT_ID : it shall be filled with your public cloud project id. If not filled, it will be requested on script startup. 16 | 17 | If other pre requisites are needed for some use case, a specific README is present in the example folder. 18 | 19 | ## Folder structure 20 | One folder per example. In order to run the example, you should go in the example subdirectory and run `terraform init` and `terraform apply` 21 | 22 | # Notes/Disclaimer 23 | 24 | * Those scripts do not follow terraform best practices to split the project in multiple files e.g. provider.tf, main.tf, variables.tf, outputs.tf, ... This has been done intentionnaly to avoid switching into multiples files for what are a really simple examples. 25 | * The secret that is created by this script is stored in the [local](https://developer.hashicorp.com/terraform/language/settings/backends/local) state back-end. If you use this back-end in production, be sure to consider the state file as a secret. 26 | 27 | # License 28 | 29 | Copyright 2022-2023 OVH SAS 30 | 31 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 32 | 33 | http://www.apache.org/licenses/LICENSE-2.0 34 | 35 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -------------------------------------------------------------------------------- /simple_http_lb_with_prom_grafana/variables.tf: -------------------------------------------------------------------------------- 1 | 2 | variable "ovh_public_cloud_project_id" { 3 | type = string 4 | description = "the id of your public cloud project. It can be found on the upper left in OVHCloud Control Plane below your project name" 5 | } 6 | 7 | variable "openstack_region" { 8 | type = string 9 | description = "the openstack region on which the infrastructure will be deployed. You can view the openstack regions in the OVHCloud Control Plane in the 'Quotas and Regions' panel " 10 | default = "GRA11" 11 | } 12 | 13 | variable "dns_subdomain" { 14 | type = string 15 | description = "the subdomain below the zone" 16 | default = "lbdemo" 17 | } 18 | 19 | variable "dns_zone" { 20 | type = string 21 | description = "the zone that will be used to host the sub domain" 22 | } 23 | 24 | variable "resource_prefix" { 25 | type = string 26 | description = "the prefix that is used for all the created resources" 27 | default = "tf_lb_with_prom_and_grafana_" 28 | } 29 | variable "image_name" { 30 | type = string 31 | description = "The image used for the instances" 32 | default = "Ubuntu 22.04" 33 | } 34 | variable "instance_type" { 35 | type = string 36 | description = "the instances type" 37 | default = "d2-2" 38 | } 39 | variable "external_network" { 40 | type = string 41 | description = "The name of the network that is used to connect a private network to internet. This should normally not be changed" 42 | default = "Ext-Net" 43 | } 44 | 45 | variable "instance_nb" { 46 | type = number 47 | description = "The number of http instance that will be answering to http requests behind the load balancer" 48 | default = 2 49 | } 50 | 51 | variable "prometheus_version" { 52 | type = string 53 | description = "The version of prometheus that is downloaded and installed" 54 | default = "2.37.8" 55 | } 56 | variable "acme_disable_complete_propagation" { 57 | type = bool 58 | description = "Disable the propagation of the ACME Let's Encrypt DNS challenge" 59 | default = "false" 60 | } 61 | 62 | variable "acme_email_address" { 63 | type = string 64 | description = "The email adresse used in the ACME Let's Encrypt process " 65 | } 66 | -------------------------------------------------------------------------------- /simple_http_lb_with_prom_grafana/providers.tf: -------------------------------------------------------------------------------- 1 | ####################################################################################### 2 | # Providers 3 | ######################################################################################## 4 | # Define providers and set versions 5 | terraform { 6 | required_version = ">= 0.14.0" # Takes into account Terraform versions from 0.14.0 7 | required_providers { 8 | openstack = { 9 | source = "terraform-provider-openstack/openstack" 10 | version = "~> 2.0.0" 11 | } 12 | ovh = { 13 | source = "ovh/ovh" 14 | version = "~> 0.45.0" 15 | } 16 | grafana = { 17 | source = "grafana/grafana" 18 | version = "~> 1.39.0" 19 | } 20 | dns = { 21 | version = "~> 3.3.2" 22 | } 23 | acme = { 24 | source = "vancluever/acme" 25 | version = "~> 2.0" 26 | } 27 | } 28 | } 29 | 30 | # Configure the OpenStack provider hosted by OVHcloud 31 | provider "openstack" { 32 | auth_url = "https://auth.cloud.ovh.net/v3/" # Authentication URL 33 | domain_name = "Default" # Domain name - Always at 'default' for OVHcloud 34 | user_domain_name = "Default" 35 | user_name = ovh_cloud_project_user.user.username 36 | password = ovh_cloud_project_user.user.password 37 | region = var.openstack_region 38 | tenant_id = var.ovh_public_cloud_project_id 39 | } 40 | 41 | provider "grafana" { 42 | url = "https://${openstack_networking_floatingip_v2.tf_lb_floatingip.address}:${openstack_lb_listener_v2.graf_listener.protocol_port}" 43 | # This is requested because the cert is issued for the database.cloud.ovh.net domain 44 | insecure_skip_verify = true 45 | org_id = "3" 46 | auth = "${ovh_cloud_project_database_user.avnadmin.name}:${ovh_cloud_project_database_user.avnadmin.password}" 47 | } 48 | 49 | provider "acme" { 50 | server_url = "https://acme-v02.api.letsencrypt.org/directory" 51 | } 52 | 53 | ######################################################################################## 54 | # User 55 | ######################################################################################## 56 | resource "ovh_cloud_project_user" "user" { 57 | service_name = var.ovh_public_cloud_project_id 58 | description = "User created by terraform loadbalancer script" 59 | role_name = "administrator" 60 | } -------------------------------------------------------------------------------- /simple_http_lb_with_prom_grafana/instances.tf: -------------------------------------------------------------------------------- 1 | ######################################################################################## 2 | # Instances 3 | ######################################################################################## 4 | 5 | 6 | # Creating the instance, no SSH keys 7 | resource "openstack_compute_instance_v2" "http_server" { 8 | count = var.instance_nb 9 | name = "${var.resource_prefix}http_server_${count.index}" # Instance name 10 | image_name = var.image_name # Image name 11 | flavor_name = var.instance_type # Instance type name 12 | network { 13 | name = openstack_networking_network_v2.tf_lb_network.name 14 | } 15 | user_data = <Load Balanced Member 1

You did it ! You hit your OVHCloud load balancer member #${count.index} !

' | sudo tee /var/www/html/index.html 21 | echo 'user data end' 22 | EOF 23 | # Add dependency on router itf to be sure the instance can access internet to retrieve package in user data 24 | depends_on = [openstack_networking_router_interface_v2.tf_lb_router_itf_priv] 25 | } 26 | 27 | resource "openstack_compute_instance_v2" "prometheus" { 28 | name = "${var.resource_prefix}prometheus" # Instance name 29 | image_name = var.image_name # Image name 30 | flavor_name = var.instance_type # Instance type name 31 | network { 32 | name = openstack_networking_network_v2.tf_lb_network.name 33 | } 34 | user_data = <> prometheus.yml 44 | ./prometheus --config.file=prometheus.yml& 45 | EOF 46 | # Add dependency on router itf to be sure the instance can access internet to retrieve package in user data 47 | depends_on = [openstack_networking_router_interface_v2.tf_lb_router_itf_priv] 48 | } -------------------------------------------------------------------------------- /private_network/private_network.tf: -------------------------------------------------------------------------------- 1 | ######################################################################################## 2 | # This script creates an S3 bucket along with 1 S3 user 3 | # 4 | # It requires the following variables to be defined for the OVH provider : 5 | # OVH_ENDPOINT 6 | # OVH_APPLICATION_KEY 7 | # OVH_APPLICATION_SECRET 8 | # OVH_CONSUMER_KEY 9 | # The following is required specifically for this script: 10 | # TF_VAR_OVH_PUBLIC_CLOUD_PROJECT_ID that shall be filled with your public cloud project id or it will be requested on script startup 11 | # TF_VAR_VRACK_ID with a vrack id to which the cloud project will be attached or it will be requested on script startup 12 | ######################################################################################## 13 | 14 | 15 | ######################################################################################## 16 | # Variables 17 | ######################################################################################## 18 | variable "ovh_public_cloud_project_id" { 19 | type = string 20 | } 21 | 22 | 23 | variable "openstack_region" { 24 | type = string 25 | default = "GRA9" 26 | } 27 | 28 | variable "user_desc_prefix" { 29 | type = string 30 | default = "[TF] User created by s3 terraform script" 31 | } 32 | 33 | variable "vlan_id" { 34 | type = number 35 | default = "42" 36 | } 37 | 38 | 39 | ####################################################################################### 40 | # Providers 41 | ######################################################################################## 42 | terraform { 43 | required_providers { 44 | openstack = { 45 | source = "terraform-provider-openstack/openstack" 46 | version = "~> 2.0.0" 47 | } 48 | 49 | ovh = { 50 | source = "ovh/ovh" 51 | version = "~> 0.45.0" 52 | } 53 | } 54 | } 55 | # Configure the OpenStack expoprovider hosted by OVHcloud 56 | provider "openstack" { 57 | auth_url = "https://auth.cloud.ovh.net/v3/" # Authentication URL 58 | domain_name = "Default" # Domain name - Always at 'default' for OVHcloud 59 | user_domain_name = "Default" 60 | user_name = ovh_cloud_project_user.user.username 61 | password = ovh_cloud_project_user.user.password 62 | region = var.openstack_region 63 | tenant_id = var.ovh_public_cloud_project_id 64 | } 65 | 66 | ######################################################################################## 67 | # User / Credential 68 | ######################################################################################## 69 | resource "ovh_cloud_project_user" "user" { 70 | service_name = var.ovh_public_cloud_project_id 71 | description = "${var.user_desc_prefix} that is used to manage network" 72 | role_name = "network_operator" 73 | } 74 | 75 | ######################################################################################## 76 | # Network 77 | ######################################################################################## 78 | 79 | resource "openstack_networking_network_v2" "tf_network" { 80 | name = "tf_network" 81 | admin_state_up = "true" 82 | value_specs = { 83 | "provider:network_type" = "vrack" 84 | "provider:segmentation_id" = var.vlan_id 85 | } 86 | 87 | } 88 | 89 | resource "openstack_networking_subnet_v2" "tf_subnet" { 90 | name = "tf_subnet" 91 | network_id = openstack_networking_network_v2.tf_network.id 92 | cidr = "10.0.0.0/16" 93 | enable_dhcp = true 94 | } 95 | 96 | -------------------------------------------------------------------------------- /simple_http_lb_with_prom_grafana/loadbalancer.tf: -------------------------------------------------------------------------------- 1 | 2 | ######################################################################################## 3 | # Loadbalancers 4 | ######################################################################################## 5 | data "openstack_loadbalancer_flavor_v2" "flavor" { 6 | name = "small" 7 | depends_on = [ 8 | ovh_cloud_project_user.user 9 | ] 10 | } 11 | 12 | 13 | resource "openstack_lb_loadbalancer_v2" "tf_lb" { 14 | name = "${var.resource_prefix}_lb" 15 | flavor_id = data.openstack_loadbalancer_flavor_v2.flavor.flavor_id 16 | vip_network_id = openstack_networking_network_v2.tf_lb_network.id 17 | vip_subnet_id = openstack_networking_subnet_v2.tf_lb_subnet.id 18 | } 19 | 20 | 21 | resource "openstack_lb_listener_v2" "http_listener" { 22 | protocol = "HTTP" 23 | protocol_port = 80 24 | loadbalancer_id = openstack_lb_loadbalancer_v2.tf_lb.id 25 | } 26 | 27 | resource "openstack_lb_listener_v2" "https_listener" { 28 | protocol = "TERMINATED_HTTPS" 29 | protocol_port = 443 30 | loadbalancer_id = openstack_lb_loadbalancer_v2.tf_lb.id 31 | default_tls_container_ref = openstack_keymanager_secret_v1.tls_secret.secret_ref 32 | } 33 | 34 | #second listener to expose grafana 35 | resource "openstack_lb_listener_v2" "graf_listener" { 36 | protocol = "HTTPS" 37 | protocol_port = 8443 38 | loadbalancer_id = openstack_lb_loadbalancer_v2.tf_lb.id 39 | } 40 | 41 | resource "openstack_lb_listener_v2" "prom_listener" { 42 | protocol = "PROMETHEUS" 43 | protocol_port = 8088 44 | loadbalancer_id = openstack_lb_loadbalancer_v2.tf_lb.id 45 | #restrict the access of the listener to the private network subnet 46 | allowed_cidrs = [openstack_networking_subnet_v2.tf_lb_subnet.cidr] 47 | } 48 | 49 | 50 | resource "openstack_lb_pool_v2" "main_pool" { 51 | name = "${var.resource_prefix}main_pool" 52 | protocol = "HTTP" 53 | lb_method = "ROUND_ROBIN" 54 | listener_id = openstack_lb_listener_v2.https_listener.id 55 | } 56 | 57 | resource "openstack_lb_pool_v2" "graf_pool" { 58 | name = "${var.resource_prefix}graf_pool" 59 | protocol = "HTTPS" 60 | lb_method = "ROUND_ROBIN" 61 | listener_id = openstack_lb_listener_v2.graf_listener.id 62 | 63 | } 64 | 65 | resource "openstack_lb_l7policy_v2" "redirect_http_policy" { 66 | name = "redirect_http_policy" 67 | action = "REDIRECT_TO_URL" 68 | position = 1 69 | listener_id = openstack_lb_listener_v2.http_listener.id 70 | redirect_url = "https://${var.dns_subdomain}.${var.dns_zone}" 71 | } 72 | 73 | resource "openstack_lb_l7rule_v2" "redirect_http_rule" { 74 | l7policy_id = openstack_lb_l7policy_v2.redirect_http_policy.id 75 | type = "PATH" 76 | compare_type = "STARTS_WITH" 77 | value = "/" 78 | } 79 | resource "openstack_lb_monitor_v2" "monitor_1" { 80 | pool_id = openstack_lb_pool_v2.main_pool.id 81 | type = "HTTP" 82 | url_path = "/index.html" 83 | delay = 5 84 | timeout = 10 85 | max_retries = 4 86 | } 87 | 88 | resource "openstack_lb_member_v2" "main_member" { 89 | count = var.instance_nb 90 | name = "member_${count.index}" 91 | pool_id = openstack_lb_pool_v2.main_pool.id 92 | address = openstack_compute_instance_v2.http_server[count.index].access_ip_v4 93 | protocol_port = 80 94 | subnet_id = openstack_networking_subnet_v2.tf_lb_subnet.id 95 | } 96 | 97 | resource "openstack_lb_member_v2" "graf_member" { 98 | name = "graf_member" 99 | pool_id = openstack_lb_pool_v2.graf_pool.id 100 | address = data.dns_a_record_set.grafana.addrs[0] 101 | protocol_port = 443 102 | subnet_id = openstack_networking_subnet_v2.tf_lb_subnet.id 103 | } 104 | 105 | resource "ovh_domain_zone_record" "record" { 106 | zone = var.dns_zone 107 | subdomain = var.dns_subdomain 108 | fieldtype = "A" 109 | ttl = "3600" 110 | target = openstack_networking_floatingip_v2.tf_lb_floatingip.address 111 | } -------------------------------------------------------------------------------- /s3_bucket_only/s3_bucket_only.tf: -------------------------------------------------------------------------------- 1 | ######################################################################################## 2 | # This script creates an S3 bucket along with 1 S3 user 3 | # 4 | # It requires the following variables to be defined for the OVH provider : 5 | # OVH_ENDPOINT 6 | # OVH_APPLICATION_KEY 7 | # OVH_APPLICATION_SECRET 8 | # OVH_CONSUMER_KEY 9 | # The following is required specifically for this script: 10 | # TF_VAR_OVH_PUBLIC_CLOUD_PROJECT_ID that shall be filled with your public cloud project id or it will be requested on script startup 11 | ######################################################################################## 12 | 13 | 14 | ######################################################################################## 15 | # Variables 16 | ######################################################################################## 17 | variable "ovh_public_cloud_project_id" { 18 | type = string 19 | } 20 | 21 | variable "region" { 22 | type = string 23 | default = "gra" 24 | } 25 | 26 | variable "s3_endpoint" { 27 | type = string 28 | default = "https://s3.gra.io.cloud.ovh.net" 29 | } 30 | 31 | variable "user_desc_prefix" { 32 | type = string 33 | default = "[TF] User created by s3 terraform script" 34 | } 35 | 36 | variable "bucket_name" { 37 | type = string 38 | default = "tf-s3-bucket-only" 39 | } 40 | 41 | 42 | ####################################################################################### 43 | # Providers 44 | ######################################################################################## 45 | 46 | terraform { 47 | required_providers { 48 | aws = { 49 | source = "hashicorp/aws" 50 | version = "~> 4.0" 51 | } 52 | 53 | ovh = { 54 | source = "ovh/ovh" 55 | version = "~> 0.45.0" 56 | } 57 | } 58 | } 59 | 60 | # Configure the AWS Provider 61 | provider "aws" { 62 | region = var.region 63 | access_key = ovh_cloud_project_user_s3_credential.s3_admin_cred.access_key_id 64 | secret_key = ovh_cloud_project_user_s3_credential.s3_admin_cred.secret_access_key 65 | 66 | #OVH implementation has no STS service 67 | skip_credentials_validation = true 68 | skip_requesting_account_id = true 69 | # the gra region is unknown to AWS hence skipping is needed. 70 | skip_region_validation = true 71 | endpoints { 72 | s3 = var.s3_endpoint 73 | } 74 | } 75 | 76 | 77 | ######################################################################################## 78 | # User / Credential 79 | ######################################################################################## 80 | resource "ovh_cloud_project_user" "s3_admin_user" { 81 | service_name = var.ovh_public_cloud_project_id 82 | description = "${var.user_desc_prefix} that is used to create S3 access key" 83 | role_name = "objectstore_operator" 84 | } 85 | resource "ovh_cloud_project_user_s3_credential" "s3_admin_cred" { 86 | service_name = var.ovh_public_cloud_project_id 87 | user_id = ovh_cloud_project_user.s3_admin_user.id 88 | } 89 | 90 | ######################################################################################## 91 | # Bucket 92 | ######################################################################################## 93 | resource "aws_s3_bucket" "b" { 94 | bucket = "${var.ovh_public_cloud_project_id}-${var.bucket_name}" 95 | } 96 | 97 | resource "aws_s3_bucket_server_side_encryption_configuration" "example" { 98 | bucket = aws_s3_bucket.b.id 99 | rule { 100 | apply_server_side_encryption_by_default { 101 | sse_algorithm = "AES256" 102 | } 103 | } 104 | } 105 | 106 | 107 | ######################################################################################## 108 | # Output 109 | ######################################################################################## 110 | output "access_key" { 111 | description = "the access key that have been created by the terraform script" 112 | value = ovh_cloud_project_user_s3_credential.s3_admin_cred.access_key_id 113 | } 114 | 115 | output "secret_key" { 116 | description = "the secret key that have been created by the terraform script" 117 | value = ovh_cloud_project_user_s3_credential.s3_admin_cred.secret_access_key 118 | sensitive = true 119 | } 120 | -------------------------------------------------------------------------------- /simple_http_lb_with_prom_grafana/README.md: -------------------------------------------------------------------------------- 1 | # Objectives 2 | 3 | The objectives of this example are to show: 4 | * how to use terraform with [Public Cloud Load Balancer](https://www.ovhcloud.com/en/public-cloud/load-balancer/) 5 | * how to set up the [Load Balancer built in Prometheus listener](https://docs.openstack.org/octavia/latest/user/guides/monitoring.html#monitoring-with-prometheus) to monitor it 6 | * how to connect this listener to a prometheus and to a [Grafana managed instance](https://www.ovhcloud.com/en/public-cloud/grafana/) 7 | 8 | 9 | # Description 10 | 11 | This example creates: 12 | - an openstack user that will be used to create the whole infrastructure 13 | - a private network 14 | - a Public Gateway and a floating IP that will be used to receive the incoming traffic on the load balancer 15 | - an HTTP load balancer with 4 listeners : 16 | - 80 for HTTP traffic (that is redirected to HTTPS thanks to a L7 rule), 17 | - 443 for the HTTPS load balanced traffic, 18 | - 8088 for the prometheus metrics (this listener is protected to be accessible only from the private network), 19 | - 80443 to expose the Grafana UI on the internet (because the instance is deployed in the private network) 20 | - 2 HTTP servers (the number of HTTP server can changed using the `instance_nb` variable) 21 | - an instance that will run prometheus to scrape the metrics from the load balancer and to make them available on Grafana 22 | - a Grafana managed instance on which the opensource [dashboard](https://grafana.com/grafana/dashboards/15828-octavia-amphora-load-balancer/) is deployed. 23 | - a certificate that is retrieved from Let's Encrypt service. 24 | 25 | The architecture is the following: 26 | 27 | ![that](img/architecture.png) 28 | 29 | # Inputs / prerequisites 30 | 31 | You will need to have `terraform` binary in your `PATH`. Installation doc is available on [Hashicorp website](https://developer.hashicorp.com/terraform/downloads) 32 | This script requires the following variables to be defined for the OVH provider : 33 | - OVH_ENDPOINT 34 | - OVH_APPLICATION_KEY 35 | - OVH_APPLICATION_SECRET 36 | - OVH_CONSUMER_KEY 37 | 38 | Look at the [ovh provider documentation](https://registry.terraform.io/providers/ovh/ovh/latest/docs) to generate the values for those variables. 39 | 40 | Additionaly the variables are needed or will be requested on script startup : 41 | - `TF_VAR_ovh_public_cloud_project_id` your public cloud project id. You can find in this [documentation page](https://help.ovhcloud.com/csm/en-gb-public-cloud-compute-create-project?id=kb_article_view&sysparm_article=KB0050592) how to create your first public cloud project. 42 | - `TF_VAR_dns_zone` the OVH DNS zone where the load balancer record will be created with the created floating ip 43 | - `TF_VAR_acme_email_address` the email adress used for the Let's Encrypt registration 44 | 45 | # Limitations 46 | 47 | - When interacting with Grafana, HTTPS is used with a self signed certificate which means that will receive a security message from your browser. 48 | - The secrets that are managed by this script are stored in the state [backend](https://developer.hashicorp.com/terraform/language/settings/backends/configuration) (by default a local file). If you use this example in production, be sure to consider the state backend as tool that manages secrets. 49 | 50 | # Outputs 51 | 52 | Run `terraform init` and `terraform apply` to launch the infrastructure provisionning. 53 | The outputs are : 54 | - the URL to be used for the HTTP load balancer : if you reload the page, you should see that the member that is handling the request has changed (courtesy of the round robin algorithm). 55 | - the URL for the Grafana service. 56 | - the user to login to the Grafana service. 57 | - the password to login to the Grafana service. Since it is sensitive, to see it, you need to run `terraform output -raw grafana_password` 58 | 59 | # Looking at your load balancer metrics 60 | - Connect to the Grafana URL provided as output, accept the self signed certificate, log in using the user / password provided as output 61 | - Now you are in Grafana dashboard page, choose the `OpenStack Octavia Amphora Load Balancer` and you should see something like 62 | 63 | ![Grafana dashboard](img/dashboard.png) 64 | - If you want to see the metrics figures increase, you can use a stress tool like [wrk](https://github.com/wg/wrk) 65 | 66 | # Costs 67 | At the time of this writing (May 2023), the hourly [prices](https://www.ovhcloud.com/en-ie/public-cloud/prices/) are : 68 | - 1 small gateway (€0.0028) 69 | - 1 floating IP (€0.0025) 70 | - 1 small load balancer (€0.0083) 71 | - 3 d2-2 instances (3*€0.0099) 72 | - 1 Grafana (€0.0591) 73 | 74 | So running this example for one hour will cost you around € 0.10 ! 75 | 76 | 77 | -------------------------------------------------------------------------------- /s3_policy/s3_policy.tf: -------------------------------------------------------------------------------- 1 | ######################################################################################## 2 | # This script creates an S3 bucket along with 3 S3 users and gives differents policies to the different users 3 | # 4 | # It requires the following variables to be defined for the OVH provider : 5 | # OVH_ENDPOINT 6 | # OVH_APPLICATION_KEY 7 | # OVH_APPLICATION_SECRET 8 | # OVH_CONSUMER_KEY 9 | # The following is required specifically for this script: 10 | # TF_VAR_OVH_PUBLIC_CLOUD_PROJECT_ID that shall be filled with your public cloud project id or it will be requested on script startup 11 | ######################################################################################## 12 | 13 | 14 | ######################################################################################## 15 | # Variables 16 | ######################################################################################## 17 | variable "ovh_public_cloud_project_id" { 18 | type = string 19 | } 20 | 21 | variable "region" { 22 | type = string 23 | default = "gra" 24 | } 25 | 26 | variable "s3_endpoint" { 27 | type = string 28 | default = "https://s3.gra.io.cloud.ovh.net" 29 | } 30 | 31 | variable "user_desc_prefix" { 32 | type = string 33 | default = "[TF] User created by s3 terraform script" 34 | } 35 | 36 | variable "bucket_name" { 37 | type = string 38 | default = "tf-s3-bucket-policy" 39 | } 40 | variable "object_name" { 41 | type = string 42 | default = "test_file.txt" 43 | } 44 | 45 | 46 | ####################################################################################### 47 | # Providers 48 | ######################################################################################## 49 | 50 | terraform { 51 | required_providers { 52 | aws = { 53 | source = "hashicorp/aws" 54 | version = "~> 4.0" 55 | } 56 | 57 | ovh = { 58 | source = "ovh/ovh" 59 | 60 | } 61 | } 62 | } 63 | 64 | # Configure the AWS Provider 65 | provider "aws" { 66 | region = var.region 67 | access_key = ovh_cloud_project_user_s3_credential.s3_admin_cred.access_key_id 68 | secret_key = ovh_cloud_project_user_s3_credential.s3_admin_cred.secret_access_key 69 | 70 | #OVH implementation has no STS service 71 | skip_credentials_validation = true 72 | skip_requesting_account_id = true 73 | # the gra region is unknown to AWS hence skipping is needed. 74 | skip_region_validation = true 75 | endpoints { 76 | s3 = var.s3_endpoint 77 | } 78 | } 79 | 80 | 81 | ######################################################################################## 82 | # User / Credential 83 | ######################################################################################## 84 | resource "ovh_cloud_project_user" "s3_admin_user" { 85 | service_name = var.ovh_public_cloud_project_id 86 | description = "${var.user_desc_prefix} that is used to create S3 bucket" 87 | role_name = "objectstore_operator" 88 | } 89 | resource "ovh_cloud_project_user_s3_credential" "s3_admin_cred" { 90 | service_name = var.ovh_public_cloud_project_id 91 | user_id = ovh_cloud_project_user.s3_admin_user.id 92 | } 93 | resource "ovh_cloud_project_user" "write_user" { 94 | service_name = var.ovh_public_cloud_project_id 95 | description = "${var.user_desc_prefix} that will have write access to the bucket" 96 | role_name = "objectstore_operator" 97 | } 98 | 99 | resource "ovh_cloud_project_user_s3_credential" "write_cred" { 100 | service_name = var.ovh_public_cloud_project_id 101 | user_id = ovh_cloud_project_user.write_user.id 102 | } 103 | 104 | resource "ovh_cloud_project_user" "read_user" { 105 | service_name = var.ovh_public_cloud_project_id 106 | description = "${var.user_desc_prefix} that will have read access to the bucket" 107 | role_name = "objectstore_operator" 108 | } 109 | resource "ovh_cloud_project_user_s3_credential" "read_cred" { 110 | service_name = var.ovh_public_cloud_project_id 111 | user_id = ovh_cloud_project_user.read_user.id 112 | } 113 | 114 | 115 | ######################################################################################## 116 | # Bucket 117 | ######################################################################################## 118 | resource "aws_s3_bucket" "b" { 119 | bucket = "${var.ovh_public_cloud_project_id}-${var.bucket_name}" 120 | } 121 | 122 | resource "aws_s3_object" "object" { 123 | bucket = aws_s3_bucket.b.bucket 124 | key = var.object_name 125 | content = "This is a small text, used to test the object from terraform" 126 | } 127 | ######################################################################################## 128 | # Policy 129 | ######################################################################################## 130 | 131 | resource "ovh_cloud_project_user_s3_policy" "write_policy" { 132 | service_name = var.ovh_public_cloud_project_id 133 | user_id = ovh_cloud_project_user.write_user.id 134 | policy = jsonencode({ 135 | "Statement" : [{ 136 | "Sid" : "RWContainer", 137 | "Effect" : "Allow", 138 | "Action" : ["s3:GetObject", "s3:PutObject", "s3:DeleteObject", "s3:ListBucket", "s3:ListMultipartUploadParts", "s3:ListBucketMultipartUploads", "s3:AbortMultipartUpload", "s3:GetBucketLocation"], 139 | "Resource" : ["arn:aws:s3:::${aws_s3_bucket.b.bucket}", "arn:aws:s3:::${aws_s3_bucket.b.bucket}/*"] 140 | }] 141 | }) 142 | } 143 | 144 | resource "ovh_cloud_project_user_s3_policy" "read_policy" { 145 | service_name = var.ovh_public_cloud_project_id 146 | user_id = ovh_cloud_project_user.read_user.id 147 | policy = jsonencode({ 148 | "Statement" : [{ 149 | "Sid" : "ROContainer", 150 | "Effect" : "Allow", 151 | "Action" : ["s3:GetObject", "s3:ListBucket", "s3:ListMultipartUploadParts", "s3:ListBucketMultipartUploads"], 152 | "Resource" : ["arn:aws:s3:::${aws_s3_bucket.b.bucket}", "arn:aws:s3:::${aws_s3_bucket.b.bucket}/*"] 153 | }] 154 | }) 155 | } 156 | 157 | ######################################################################################## 158 | # Output 159 | ######################################################################################## 160 | output "admin_access_key" { 161 | description = "the access key that have been used to create the bucket" 162 | value = ovh_cloud_project_user_s3_credential.s3_admin_cred.access_key_id 163 | } 164 | 165 | output "admin_secret_key" { 166 | description = "the secret key that have been used to create the bucket" 167 | value = ovh_cloud_project_user_s3_credential.s3_admin_cred.secret_access_key 168 | sensitive = true 169 | } 170 | 171 | output "read_user_access_key" { 172 | description = "the access key for the user that have been provided read access to the bucket" 173 | value = ovh_cloud_project_user_s3_credential.read_cred.access_key_id 174 | } 175 | 176 | output "read_user_secret_key" { 177 | description = "the secret key for the user that have been provided read access to the bucket" 178 | value = ovh_cloud_project_user_s3_credential.read_cred.secret_access_key 179 | sensitive = true 180 | } 181 | 182 | output "write_user_access_key" { 183 | description = "the access key for the user that have been provided write access to the bucket" 184 | value = ovh_cloud_project_user_s3_credential.write_cred.access_key_id 185 | } 186 | 187 | output "write_user_secret_key" { 188 | description = "the secret key for the user that have been provided write access to the bucket" 189 | value = ovh_cloud_project_user_s3_credential.write_cred.secret_access_key 190 | sensitive = true 191 | } 192 | 193 | -------------------------------------------------------------------------------- /simple_http_lb/simple_http_lb.tf: -------------------------------------------------------------------------------- 1 | ######################################################################################## 2 | # This script requires the following variables to be defined for the OVH provider : 3 | # OVH_ENDPOINT 4 | # OVH_APPLICATION_KEY 5 | # OVH_APPLICATION_SECRET 6 | # OVH_CONSUMER_KEY 7 | # The following is required specifically for this script: 8 | # TF_VAR_OVH_PUBLIC_CLOUD_PROJECT_ID that shall be filled with your public cloud project id or it will be requested on script startup 9 | ######################################################################################## 10 | 11 | 12 | ######################################################################################## 13 | # Variables 14 | ######################################################################################## 15 | 16 | variable "ovh_public_cloud_project_id" { 17 | type = string 18 | } 19 | 20 | variable "openstack_region" { 21 | type = string 22 | default = "GRA9" 23 | } 24 | 25 | variable "resource_prefix" { 26 | type = string 27 | default = "tf_at_ovhcloud_simple_http_lb_" 28 | } 29 | variable "image_name" { 30 | type = string 31 | default = "Ubuntu 22.04" 32 | } 33 | variable "instance_type" { 34 | type = string 35 | default = "d2-2" 36 | } 37 | variable "external_network" { 38 | type = string 39 | default = "Ext-Net" 40 | } 41 | 42 | variable "instance_nb" { 43 | default = 2 44 | } 45 | 46 | variable "stream_id" { 47 | type = string 48 | default = null 49 | description = "the stream id to which the logs shall be sent. If null, no log subcription is created" 50 | } 51 | 52 | ####################################################################################### 53 | # Providers 54 | ######################################################################################## 55 | # Define providers and set versions 56 | terraform { 57 | required_version = ">= 0.14.0" # Takes into account Terraform versions from 0.14.0 58 | required_providers { 59 | openstack = { 60 | source = "terraform-provider-openstack/openstack" 61 | version = "~> 2.0.0" 62 | } 63 | ovh = { 64 | source = "ovh/ovh" 65 | version = "~> 0.48.0" 66 | } 67 | } 68 | } 69 | 70 | # Configure the OpenStack expoprovider hosted by OVHcloud 71 | provider "openstack" { 72 | auth_url = "https://auth.cloud.ovh.net/v3/" # Authentication URL 73 | domain_name = "Default" # Domain name - Always at 'default' for OVHcloud 74 | user_domain_name = "Default" 75 | user_name = ovh_cloud_project_user.user.username 76 | password = ovh_cloud_project_user.user.password 77 | region = var.openstack_region 78 | tenant_id = var.ovh_public_cloud_project_id 79 | } 80 | 81 | 82 | ######################################################################################## 83 | # User 84 | ######################################################################################## 85 | resource "ovh_cloud_project_user" "user" { 86 | service_name = var.ovh_public_cloud_project_id 87 | description = "User created by terraform loadbalancer script" 88 | role_name = "administrator" 89 | } 90 | 91 | ######################################################################################## 92 | # Instances 93 | ######################################################################################## 94 | 95 | 96 | # Creating the instance, no SSH keys 97 | resource "openstack_compute_instance_v2" "http_server" { 98 | count = var.instance_nb 99 | name = "${var.resource_prefix}http_server_${count.index}" # Instance name 100 | image_name = var.image_name # Image name 101 | flavor_name = var.instance_type # Instance type name 102 | network { 103 | name = openstack_networking_network_v2.tf_lb_network.name 104 | } 105 | user_data = <Load Balanced Member 1

You did it ! You hit your OVHCloud load balancer member #${count.index} !

' | sudo tee /var/www/html/index.html 111 | echo 'user data end' 112 | EOF 113 | # Add dependency on router itf to be sure the instance can access internet to retrieve package in user data 114 | depends_on = [openstack_networking_router_interface_v2.tf_lb_router_itf_priv] 115 | lifecycle { 116 | # OVHcloud met régulièrement à jour l’image de base d’un OS donné afin que le client ait moins de paquets à mettre à jour après le lancement d’une nouvelle instance 117 | # Pour éviter que terraform ne rencontre des problèmes avec cela, la commande ignore_changes suivante est requise. 118 | ignore_changes = [ 119 | image_name 120 | ] 121 | } 122 | } 123 | 124 | ######################################################################################## 125 | # Network 126 | ######################################################################################## 127 | data "openstack_networking_network_v2" "ext_net" { 128 | name = var.external_network 129 | external = true 130 | depends_on = [ 131 | ovh_cloud_project_user.user 132 | ] 133 | } 134 | 135 | resource "openstack_networking_network_v2" "tf_lb_network" { 136 | name = "${var.resource_prefix}network" 137 | admin_state_up = "true" 138 | } 139 | 140 | 141 | resource "openstack_networking_subnet_v2" "tf_lb_subnet" { 142 | name = "tf_lb_subnet" 143 | network_id = openstack_networking_network_v2.tf_lb_network.id 144 | cidr = "10.0.0.0/24" 145 | gateway_ip = "10.0.0.254" 146 | dns_nameservers = ["213.186.33.99"] 147 | ip_version = 4 148 | 149 | } 150 | 151 | resource "openstack_networking_router_v2" "tf_lb_router" { 152 | name = "tf_lb_router" 153 | external_network_id = data.openstack_networking_network_v2.ext_net.id 154 | } 155 | 156 | resource "openstack_networking_floatingip_v2" "tf_lb_floatingip" { 157 | pool = data.openstack_networking_network_v2.ext_net.name 158 | } 159 | 160 | resource "openstack_networking_router_interface_v2" "tf_lb_router_itf_priv" { 161 | router_id = openstack_networking_router_v2.tf_lb_router.id 162 | subnet_id = openstack_networking_subnet_v2.tf_lb_subnet.id 163 | } 164 | 165 | resource "openstack_networking_floatingip_associate_v2" "association" { 166 | floating_ip = openstack_networking_floatingip_v2.tf_lb_floatingip.address 167 | port_id = openstack_lb_loadbalancer_v2.tf_lb.vip_port_id 168 | 169 | } 170 | 171 | ######################################################################################## 172 | # Loadbalancers 173 | ######################################################################################## 174 | data "openstack_loadbalancer_flavor_v2" "flavor" { 175 | name = "small" 176 | depends_on = [ 177 | ovh_cloud_project_user.user 178 | ] 179 | } 180 | 181 | resource "openstack_lb_loadbalancer_v2" "tf_lb" { 182 | name = "terraform_lb" 183 | flavor_id = data.openstack_loadbalancer_flavor_v2.flavor.flavor_id 184 | vip_network_id = openstack_networking_network_v2.tf_lb_network.id 185 | vip_subnet_id = openstack_networking_subnet_v2.tf_lb_subnet.id 186 | } 187 | 188 | 189 | resource "openstack_lb_listener_v2" "listener_http" { 190 | protocol = "HTTP" 191 | protocol_port = 80 192 | loadbalancer_id = openstack_lb_loadbalancer_v2.tf_lb.id 193 | } 194 | 195 | resource "openstack_lb_pool_v2" "pool_1" { 196 | name = "tf_lb_pool" 197 | protocol = "HTTP" 198 | lb_method = "ROUND_ROBIN" 199 | listener_id = openstack_lb_listener_v2.listener_http.id 200 | 201 | } 202 | 203 | resource "openstack_lb_monitor_v2" "monitor_1" { 204 | pool_id = openstack_lb_pool_v2.pool_1.id 205 | type = "HTTP" 206 | url_path = "/index.html" 207 | delay = 5 208 | timeout = 10 209 | max_retries = 4 210 | } 211 | 212 | resource "openstack_lb_member_v2" "member" { 213 | count = var.instance_nb 214 | name = "member_${count.index}" 215 | pool_id = openstack_lb_pool_v2.pool_1.id 216 | address = openstack_compute_instance_v2.http_server[count.index].access_ip_v4 217 | protocol_port = 80 218 | subnet_id = openstack_networking_subnet_v2.tf_lb_subnet.id 219 | } 220 | 221 | ######################################################################################## 222 | # Logs subscription if stream_id 223 | ######################################################################################## 224 | resource "ovh_cloud_project_region_loadbalancer_log_subscription" "log_subscription" { 225 | count = var.stream_id != null ? 1 : 0 226 | region_name = var.openstack_region 227 | loadbalancer_id = openstack_lb_loadbalancer_v2.tf_lb.id 228 | kind = "haproxy" 229 | stream_id = var.stream_id 230 | } 231 | 232 | ######################################################################################## 233 | # Outputs 234 | ######################################################################################## 235 | output "lb_ip" { 236 | value = openstack_networking_floatingip_v2.tf_lb_floatingip.address 237 | description = "The loadbalancer public ip" 238 | } 239 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------