======CHPC Cloud Resources====== *[[guide:cloud:overview|Overview]] *[[guide:cloud:start|Getting Started]] *[[guide:cloud|User Guide]] *[[guide:cloud:advanced|IAC (Advanced)]] *[[guide:cloud:practices|Best Practice and Policies]] *[[guide:cloud:glossary|Glossary of Terms]] *[[guide:cloud:faq|FAQs]] ======How can I manage my OpenStack resources via code?====== An alternative to clicking about through the Horizon dashboard is available. In this guide we will cover: * Setting up your project(s) in GitLab * Creating your resources with Terraform ---- ===== Terraform projects setup in GitLab ===== For each Terraform project we will setup below, we will need to [[https://docs.gitlab.com/user/project/#create-a-blank-project|create a blank project in GitLab]]. ==== Base project ==== A good idea for setting up your OpenStack project space initially is with some base resources (if none have already been provided to you) such as your private networks, routers, subnets and required security groups. To simplify matters somewhat, below we make use of a pre-defined Terraform module that will set up most of what we will want to capture within our base project. In your empty GitLab repository (which you might call something like "base-project"), create the following files: **main.tf**: terraform { backend "http" { } required_providers { openstack = { source = "terraform-provider-openstack/openstack" version = "3.0.0" } } } provider "openstack" { # Configuration options } module "base-project" { source = "git::git@github.com:sfebruary/terraform-module-openstack-base?ref=main" public_network_name = var.public_network_name private_network_name = var.private_network_name private_network_description = var.private_network_description private_router_name = var.private_router_name private_subnet_name = var.private_subnet_name private_subnet_description = var.private_subnet_description private_subnet_cidr = var.private_subnet_cidr private_gateway_ip = var.private_gateway_ip dns_nameservers = var.dns_nameservers enable_dhcp = var.enable_dhcp dhcp_pool_start = var.dhcp_pool_start dhcp_pool_end = var.dhcp_pool_end } **settings.tfvars**: # network settings public_network_name = "Public Internet" private_network_name = "Private Research Network" private_network_description = "Private network accessible by the VMs." private_router_name = "Private Router" private_subnet_name = "Private Subnet" private_subnet_description = "Subnet for the Wireguard VPN private network" private_subnet_cidr = "10.0.0.0/24" private_gateway_ip = "10.0.0.1" dns_nameservers = ["8.8.8.8", "8.8.4.4"] enable_dhcp = true dhcp_pool_start = "10.0.0.200" dhcp_pool_end = "10.0.0.254" **variables.tf**: variable "public_network_name" { type = string default = null } variable "private_network_name" { type = string default = null } variable "private_network_description" { type = string default = null } variable "private_router_name" { type = string default = null } variable "private_subnet_name" { type = string default = null } variable "private_subnet_cidr" { type = string default = null } variable "private_subnet_description" { type = string default = null } variable "private_gateway_ip" { type = string default = null } variable "dns_nameservers" { type = list default = ["8.8.8.8", "8.8.4.4"] } variable "enable_dhcp" { type = bool default = false } variable "dhcp_pool_start" { type = string default = null } variable "dhcp_pool_end" { type = string default = null } To interact with OpenStack services via the command-line interface (CLI), environment variables must be configured. These variables store authentication credentials and other details required for OpenStack commands. The most common method is using an OpenStack RC file (openrc.sh), which can be downloaded from the landing page after logging into the Horizon dashboard: {{:guide:cloud:openstack-rc-dl.png?300|}} * Once downloaded, within your terminal **source** the openrc file, and enter your OpenStack password at the prompt. * Next, you will want to [[https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli|install the Terraform CLI]]. * Now we can proceed to initialising Terraform for this project. To do this, on GitLab navigate to "Operate", then "Terraform states" on the left menu. {{:guide:cloud:terraform-states.png?350|}} {{:guide:cloud:terraform-state-files.png?550|}} * Then click on "Copy Terraform init command" -- you will see that you require your GitLab access token for this. Copy the relevant commands and run them in your terminal session. * After successfully initialising, you will then execute "**terraform plan -var-file=settings.tfvars**". * Assuming everything looks good with the above (NB! you have the freedom to modify **settings.tfvars** to customise your specific environment), proceed to running "**terraform apply -var-file=settings.tfvars**", and type "yes" at the prompt to proceed. Once all of your base resources are in place, you may now proceed to creating virtual machines that make use of them. NB! Depending on one's workflow, additional resources such as SSH key-pairs and Security Group definitions might be good to define in this base setup too. Alternatively, they can be defined in other Terraform/GitLab projects, or setup more manually via the Horizon dashboard. ==== Single, generic, VM project ==== Now that we have some base resources defined, we can proceed to creating an OpenStack instance via the IAC approach. To illustrate the concept, we can again draw on a [[https://github.com/sfebruary/terraform-module-openstack-instance|pre-defined module for an instance]]. NB! This particular example assumes that an SSH key-pair already exists as a resource within your OpenStack project space, as well as a Security Group that allows SSH access to your instances, so be sure to create those first as they will be referenced below. Begin by [[https://docs.gitlab.com/user/project/#create-a-blank-project|creating a new, blank project in GitLab]]. Next, we want to create a few files: **main.tf**: terraform { backend "http" { } required_providers { openstack = { source = "terraform-provider-openstack/openstack" version = "3.0.0" } } } provider "openstack" { # Configuration options } module "instance-project" { source = "git::git@github.com:sfebruary/terraform-module-openstack-instance.git?ref=main" image_name = var.image_name flavor_name = var.flavor_name shortname = var.shortname key_pair_name = var.key_pair_name volume_name = var.volume_name volume_size = var.volume_size volume_type = var.volume_type volume_device_path = var.volume_device_path enable_online_resize = var.enable_online_resize public_network_name = var.public_network_name private_network_name = var.private_network_name private_subnet_name = var.private_subnet_name server_private_port_name = var.server_private_port_name server_private_ip = var.server_private_ip ssh_security_group_name = var.ssh_security_group_name admin_username = var.admin_username } **settings.tfvars**: # general instance settings image_name = "Rocky 9" flavor_name = "C4.small" shortname = "instance-project" volume_name = "SSD-volume-128" volume_size = "128" volume_type = "SSD" volume_device_path = "/dev/vdc" enable_online_resize = "true" admin_username = "rocky" # network settings public_network_name = "Public Internet" private_network_name = "Private Research Network" private_subnet_name = "Private Subnet" server_private_port_name = "instance-private-port" server_private_ip = "10.0.0.11" ssh_security_group_name = "ssh-secgroup" key_pair_name = "instance-keypair" **variables.tf**: variable "public_network_name" { type = string description = "The name of the public network" default = null } variable "private_network_name" { type = string description = "The name of the private network" default = null } variable "private_subnet_name" { type = string description = "The name of the private subnet" default = null } variable "server_private_port_name" { type = string description = "The name of the private network port for the instance" default = null } variable "server_private_ip" { type = string description = "The fixed IP address of the instance on the private network" default = null } variable "image_name" { type = string description = "The image to be used for the instance" default = null } variable "admin_username" { type = string description = "The admin username to be used for the instance" default = null } variable "shortname" { type = string description = "The shortname to assign to the instance" default = null } variable "flavor_name" { type = string description = "The flavor for the instance" default = null } variable "volume_name" { type = string description = "The volume name to assign to the device" default = null } variable "volume_size" { type = string description = "The volume size to assign to the device" default = null } variable "volume_type" { type = string description = "The volume type to assign to the device" default = null } variable "volume_device_path" { type = string description = "The path to the device associated with the volume" default = null } variable "enable_online_resize" { type = bool description = "Enable volume to be resized on the fly or not" default = null } variable "key_pair_name" { type = string description = "The name of the pre-defined key-pair to use for logging in to the nodes" default = null } variable "ssh_security_group_name" { type = string description = "The name of the security group to allow ssh access" default = null } Finally, proceed to initialise Terraform, plan and apply as we did above in the case of the base project. NB! In order to assign a publicly reachable IP address (i.e. a floating IP) to the above instance, you may either modify the above to include this to be done via code, or this may be done/managed via the Horizon dashboard too.