diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..aa75c7fb0e3f78b26e846b911433cbda408aae20 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +### Terraform ### +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log + +# Exclude all .tfvars files, which are likely to contain sentitive data, such as +# password, private keys, and other secrets. These should not be part of version +# control as they are data points which are potentially sensitive and subject +# to change depending on the environment. +# +*.tfvars + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include override files you do wish to add to version control using negated pattern +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl new file mode 100644 index 0000000000000000000000000000000000000000..2962f391eddd7300bc3978690da294fa8d7b0d87 --- /dev/null +++ b/.terraform.lock.hcl @@ -0,0 +1,21 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/terraform-provider-openstack/openstack" { + version = "1.35.0" + constraints = "~> 1.35.0" + hashes = [ + "h1:k1SCosvSICWAgRkswl83KtCycN7iP9asejWDDEQEtuk=", + "zh:04cf8800c83289a28619ac9925bc03e0ccd624f0ed68284f8bd473cf48f05ef0", + "zh:15fc2e1ea6f87d11e15aad075f3bfb7013eb63f31637f1ee317c94686c9650ec", + "zh:1b6625ce80e6d8f192c984dcf6ba7ab303e4fdab6fa5a0a5651a8a01521aa879", + "zh:4eb60013433f45fa3ef3fca314f68202e40ea3a12b0a5ccf75d8708002bbd8cd", + "zh:505a7b22c813874090ceaee1a3e7f29961d0fe5a854d90f313aec5aa4900f44a", + "zh:7be239b7e5672bd8fc3f3744bfe58dff73f8317ede349228a92dbd92b291a832", + "zh:97b21c64da2700a69b5a3d30e514d76b52fc1089a45a0e02611aadb071b6fcc1", + "zh:b45be0621b08f16236893a5bcc0e7fa1552176b299f6dbafa806f8b0ba5e4096", + "zh:cd3b4387766ab33fbf504b22e73196d5984bc647f5c8ac9483ad604cf5cd2ceb", + "zh:e3b69afe0cab18521ee11e283f783e76c02d248de40f7a25d54576f2b1643003", + "zh:f43d52db66544065040b40db6334a1dfe6c9084d87104af1b1d133f90bbf3a66", + ] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..50c300cf6866f5f9f262cd20502844965ee3a4de --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# Prerequisites + +* Install [terraform](https://www.terraform.io/downloads.html) 1.0 or greater +* Configure some application credentials in the [RC Openstack dashboard](https://dashboard.cloud.rc.uab.edu/identity/application_credentials/) +* Add a key pair (in the [Key Pairs](https://dashboard.cloud.rc.uab.edu/project/key_pairs) section) + +# Quickstart + +* Copy `terraform.tfvars.example` to `terraform.tfvars` and edit in appropriate values +* Run `terraform init` +* Run `terraform apply` diff --git a/compute.tf b/compute.tf new file mode 100644 index 0000000000000000000000000000000000000000..d721ae690c3ae3e2a0f037e78be31842e1263135 --- /dev/null +++ b/compute.tf @@ -0,0 +1,162 @@ +# data for reference image +data "openstack_images_image_v2" "base_image" { + name = var.base_image_name +} + +# data for different instance sizes + +data "openstack_compute_flavor_v2" "m1_small" { + name = "m1.small" +} + +# bastion node + +resource "openstack_compute_instance_v2" "bastion" { + name = "bastion" + image_id = data.openstack_images_image_v2.base_image.id + flavor_id = data.openstack_compute_flavor_v2.m1_small.id + key_pair = var.ssh_keypair + security_groups = [ + "default", + openstack_compute_secgroup_v2.allow_ssh.name + ] + + block_device { + # this is the image to clone from + uuid = data.openstack_images_image_v2.base_image.id + source_type = "image" + destination_type = "local" + boot_index = 0 + delete_on_termination = true + } + + block_device { + # and the volume to copy to + source_type = "blank" + destination_type = "volume" + volume_size = 10 + boot_index = 1 + delete_on_termination = true + } + + network { + uuid = openstack_networking_network_v2.public_network.id + } +} + +resource "openstack_compute_floatingip_associate_v2" "bastion_association" { + floating_ip = openstack_compute_floatingip_v2.floating_ip.address + instance_id = openstack_compute_instance_v2.bastion.id +} + +# OSD nodes + +resource "openstack_compute_instance_v2" "osd" { + count = var.osd_node_count + + name = format("osd%02d", count.index + 1) + image_id = data.openstack_images_image_v2.base_image.id + flavor_id = data.openstack_compute_flavor_v2.m1_small.id + key_pair = var.ssh_keypair + security_groups = [ + "default" + ] + + block_device { + # this is the image to clone from + uuid = data.openstack_images_image_v2.base_image.id + source_type = "image" + destination_type = "local" + boot_index = 0 + delete_on_termination = true + } + + block_device { + # and the volume to copy to + source_type = "blank" + destination_type = "volume" + volume_size = 10 + boot_index = 1 + delete_on_termination = true + } + + network { + uuid = openstack_networking_network_v2.public_network.id + } + + network { + uuid = openstack_networking_network_v2.cluster_network.id + } +} + +# MDS node + +resource "openstack_compute_instance_v2" "mds" { + count = 1 # TODO: add variables for this later + + name = format("mds%02d", count.index + 1) + image_id = data.openstack_images_image_v2.base_image.id + flavor_id = data.openstack_compute_flavor_v2.m1_small.id + key_pair = var.ssh_keypair + security_groups = [ + "default" + ] + + block_device { + # this is the image to clone from + uuid = data.openstack_images_image_v2.base_image.id + source_type = "image" + destination_type = "local" + boot_index = 0 + delete_on_termination = true + } + + block_device { + # and the volume to copy to + source_type = "blank" + destination_type = "volume" + volume_size = 10 + boot_index = 1 + delete_on_termination = true + } + + network { + uuid = openstack_networking_network_v2.public_network.id + } +} + +# MON node + +resource "openstack_compute_instance_v2" "mon" { + count = 1 # TODO: add variables for this later + + name = format("mon%02d", count.index + 1) + image_id = data.openstack_images_image_v2.base_image.id + flavor_id = data.openstack_compute_flavor_v2.m1_small.id + key_pair = var.ssh_keypair + security_groups = [ + "default" + ] + + block_device { + # this is the image to clone from + uuid = data.openstack_images_image_v2.base_image.id + source_type = "image" + destination_type = "local" + boot_index = 0 + delete_on_termination = true + } + + block_device { + # and the volume to copy to + source_type = "blank" + destination_type = "volume" + volume_size = 10 + boot_index = 1 + delete_on_termination = true + } + + network { + uuid = openstack_networking_network_v2.public_network.id + } +} diff --git a/networks.tf b/networks.tf new file mode 100644 index 0000000000000000000000000000000000000000..ba81251f76d2983ff2f8e8981f46bfc0e8d85706 --- /dev/null +++ b/networks.tf @@ -0,0 +1,48 @@ +# data source for external network + +data "openstack_networking_network_v2" "external" { + name = "uab-campus" # TODO: variable-itize this +} + +# cluster network - intercommunication for OSDs + +resource "openstack_networking_network_v2" "cluster_network" { + name = "ceph-cluster-network" + admin_state_up = "true" +} + +resource "openstack_networking_subnet_v2" "cluster_subnet" { + network_id = openstack_networking_network_v2.cluster_network.id + cidr = "10.0.100.0/24" +} + +# public network - management/filesystem network + +resource "openstack_networking_network_v2" "public_network" { + name = "ceph-public-network" + admin_state_up = "true" +} + +resource "openstack_networking_subnet_v2" "public_subnet" { + network_id = openstack_networking_network_v2.public_network.id + cidr = "10.0.0.0/24" +} + +# router + +resource "openstack_networking_router_v2" "router" { + name = "public-router" + admin_state_up = true + external_network_id = data.openstack_networking_network_v2.external.id +} + +resource "openstack_networking_router_interface_v2" "router_interface_public" { + router_id = openstack_networking_router_v2.router.id + subnet_id = openstack_networking_subnet_v2.public_subnet.id +} + +# floating ip + +resource "openstack_compute_floatingip_v2" "floating_ip" { + pool = data.openstack_networking_network_v2.external.name +} diff --git a/openstack.tf b/openstack.tf new file mode 100644 index 0000000000000000000000000000000000000000..63d5bdad57937689c664bff36fd745a5f1a730f7 --- /dev/null +++ b/openstack.tf @@ -0,0 +1,10 @@ +provider "openstack" { + auth_url = "https://keystone.cloud.rc.uab.edu:5000/v3" + user_name = var.user_name + user_domain_name = var.user_domain_name + application_credential_name = var.appcred_name + application_credential_id = var.appcred_id + application_credential_secret = var.appcred_secret + + insecure = true +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000000000000000000000000000000000000..118a6e53bfd7fb229cc7831b865248defb6d68ac --- /dev/null +++ b/outputs.tf @@ -0,0 +1,3 @@ +output "bastion_ip_address" { + value = openstack_compute_floatingip_v2.floating_ip.address +} diff --git a/securitygroups.tf b/securitygroups.tf new file mode 100644 index 0000000000000000000000000000000000000000..737af1d00ebe0777493dcb014752d25e6ae9ec67 --- /dev/null +++ b/securitygroups.tf @@ -0,0 +1,11 @@ +resource "openstack_compute_secgroup_v2" "allow_ssh" { + name = "allow ssh" + description = "allow ssh to hosts" + + rule { + from_port = 22 + to_port = 22 + ip_protocol = "tcp" + cidr = "0.0.0.0/0" + } +} diff --git a/terraform.tf b/terraform.tf new file mode 100644 index 0000000000000000000000000000000000000000..5767904ac4d8c0454f7d829698f767744450f44a --- /dev/null +++ b/terraform.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.0.1" + + required_providers { + openstack = { + source = "terraform-provider-openstack/openstack" + version = "~> 1.35.0" + } + } +} diff --git a/terraform.tfvars.example b/terraform.tfvars.example new file mode 100644 index 0000000000000000000000000000000000000000..9ecb6c766a69ffdca063a2e92e81e751bbc24ba9 --- /dev/null +++ b/terraform.tfvars.example @@ -0,0 +1,6 @@ +user_name = "openstack_user_name" +user_domain_name = "openstack_domain_name" +appcred_id = "application_credential_id" +appcred_name = "application_credential_name" +appcred_secret = "application_credential_secret" +ssh_keypair = "ssh_keypair_name" diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000000000000000000000000000000000000..e0b694a6c469b00b997cef4b58606543f0234d0b --- /dev/null +++ b/variables.tf @@ -0,0 +1,42 @@ +variable "user_name" { + type = string + description = "user name for use with openstack" +} + +variable "user_domain_name" { + type = string + default = "uab" + description = "the domain to use for the user" +} + +variable "appcred_id" { + type = string + description = "The app credential id. Get one from https://dashboard.cloud.rc.uab.edu/identity/application_credentials/" +} + +variable "appcred_name" { + type = string + description = "The name for your application credential" +} + +variable "appcred_secret" { + type = string + description = "The secret key for your application credential" +} + +variable "ssh_keypair" { + type = string + description = "ssh keypair name to use for authentication" +} + +variable "base_image_name" { + type = string + default = "sles-15-sp3-x86_64" + description = "base image to use for the cluster" +} + +variable "osd_node_count" { + type = number + default = 3 + description = "amount of OSD nodes to create" +}