Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: deploy to existing projects in selected metro #93

Merged
merged 2 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,27 @@ The user needs to provide two environment variables:

`METAL_AUTH_TOKEN` API token to access your Equinix account

`TF_VAR_api_key` API token to access your Equinix account.
`TF_VAR_api_key` API token to access your Equinix account (needed when Spot Market is enabled)

`TF_VAR_project_name` Terraform variable to identify project in your Equinix account.
`TF_VAR_project_name` or `TF_VAR_project_id` Terraform variable to identify project in your Equinix account.

Optionally the user can also provide:

`TF_VAR_metal_create_project` Terraform variable to create a project of name `TF_VAR_project_name` if it does not exist.

You can overwrite any values in variables.tf by using .tfvars files or [other means](https://www.terraform.io/language/values/variables#assigning-values-to-root-module-variables)
You can overwrite any values in `variables.tf` by using `.tfvars` files or [other means](https://www.terraform.io/language/values/variables#assigning-values-to-root-module-variables)

By default the module will create a 3 node Harvester cluster.

The Harvester console can be accessed using an Elastic IP created by the sample.

A random token and password will be generated for your example.

```sh
terraform output -raw harvester_os_password
terraform output -raw harvester_cluster_secret
```

If you provide a Rancher API URL and keys, your Harvester environment can be managed by Rancher and a kubeconfig file will be saved locally.

### Using `terraform.tfvars.example` to Override Variable Values
Expand Down
20 changes: 17 additions & 3 deletions data.tf
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
data "equinix_metal_project" "project" {
name = var.metal_create_project ? equinix_metal_project.new_project[0].name : var.project_name
count = var.metal_create_project ? 0 : 1

name = var.project_name == "" ? null : var.project_name
project_id = var.project_id == "" ? null : var.project_id

lifecycle {
precondition {
condition = !(var.project_name != "" && var.project_id != "")
error_message = "Only one of project_name or project_id can be set"
}
precondition {
condition = var.project_name != "" || var.project_id != ""
error_message = "One of project_name or project_id must be set when metal_create_project is false"
}
}
}

data "equinix_metal_ip_block_ranges" "address_block" {
project_id = local.project_id
metro = var.use_cheapest_metro ? local.cheapest_metro_price.metro : var.metro
metro = (var.spot_instance && var.use_cheapest_metro && local.cheapest_metro_price != null) ? local.cheapest_metro_price.metro : var.metro
}


Expand All @@ -30,7 +44,7 @@ data "equinix_metal_device" "join_devices" {
}

data "http" "prices" {
count = var.use_cheapest_metro ? 1 : 0
count = var.spot_instance && var.use_cheapest_metro ? 1 : 0
url = "https://api.equinix.com/metal/v1/market/spot/prices/metros"
method = "GET"
request_headers = {
Expand Down
17 changes: 9 additions & 8 deletions main.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
locals {
project_id = var.metal_create_project ? equinix_metal_project.new_project[0].id : data.equinix_metal_project.project.project_id
metro = var.use_cheapest_metro ? local.cheapest_metro_price.metro : lower(var.metro)
project_id = var.metal_create_project ? equinix_metal_project.new_project[0].id : data.equinix_metal_project.project[0].project_id
metro = (var.spot_instance && var.use_cheapest_metro && local.cheapest_metro_price != null) ? local.cheapest_metro_price.metro : lower(var.metro)
}

// IP attachment to be added to seed node, and this is subsequently assigned as Harvester vip
Expand All @@ -16,13 +16,14 @@ resource "random_password" "token" {
}

resource "equinix_metal_project" "new_project" {
count = var.metal_create_project ? 1 : 0
name = var.project_name
count = var.metal_create_project ? 1 : 0
name = var.project_name
organization_id = var.organization_id == "" ? null : var.organization_id
}

locals {
machine_size = var.plan
pricing_data = var.use_cheapest_metro ? try(jsondecode(data.http.prices[0].response_body), null) : null
pricing_data = (var.spot_instance && var.use_cheapest_metro) ? try(jsondecode(data.http.prices[0].response_body), null) : null
least_bid_price_metro = can(local.pricing_data) && can(local.pricing_data.spot_market_prices) ? flatten([for metro, machines in local.pricing_data.spot_market_prices : [
for machine, details in machines : {
metro = metro
Expand Down Expand Up @@ -64,7 +65,7 @@ resource "equinix_metal_device" "seed" {
resource "equinix_metal_spot_market_request" "seed_spot_request" {
count = var.node_count >= 1 && var.spot_instance ? 1 : 0
project_id = local.project_id
max_bid_price = var.use_cheapest_metro ? local.cheapest_metro_price.price : var.max_bid_price
max_bid_price = (var.use_cheapest_metro && local.cheapest_metro_price != null) ? local.cheapest_metro_price.price : var.max_bid_price
metro = local.metro
devices_min = 1
devices_max = 1
Expand Down Expand Up @@ -102,7 +103,7 @@ resource "equinix_metal_device" "join" {
resource "equinix_metal_spot_market_request" "join_spot_request" {
count = var.spot_instance ? var.node_count - 1 : 0
project_id = local.project_id
max_bid_price = var.use_cheapest_metro ? local.cheapest_metro_price.price : var.max_bid_price
max_bid_price = (var.use_cheapest_metro && local.cheapest_metro_price != null) ? local.cheapest_metro_price.price : var.max_bid_price
metro = local.metro
devices_min = 1
devices_max = 1
Expand Down Expand Up @@ -151,4 +152,4 @@ resource "local_file" "harvester_kubeconfig" {
count = var.rancher_api_url != "" ? 1 : 0
content = rancher2_cluster.rancher_cluster[0].kube_config
filename = "${var.hostname_prefix}-kubeconfig.yaml"
}
}
12 changes: 12 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,15 @@ output "out_of_band_hostnames" {
value = concat([data.equinix_metal_device.seed_device.sos_hostname], data.equinix_metal_device.join_devices.*.sos_hostname)
description = "Out of band hostnames for SSH access to the console"
}

output "harvester_os_password" {
value = random_password.password.result
description = "The password for the default OS user, 'rancher' (https://docs.harvesterhci.io/v1.3/install/harvester-configuration/#ospassword)"
sensitive = true
}

output "harvester_cluster_secret" {
value = random_password.token.result
description = "The cluster secret for joining nodes to the cluster (https://docs.harvesterhci.io/v1.3/install/harvester-configuration/#token)"
sensitive = true
}
2 changes: 1 addition & 1 deletion provider.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
terraform {
required_version = ">= 1.0"
required_version = ">= 1.2"
provider_meta "equinix" {
module_name = "harvester-equinix"
}
Expand Down
3 changes: 3 additions & 0 deletions terraform.tfvars.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ harvester_version = "v1.3.1"
hostname_prefix = "test-harvester"
node_count = "3"
project_name = "Harvester Labs"
# metal_create_project = false
# project_id = "uuid"
# organization_id = "uuid"
plan = "m3.small.x86"
#max_bid_price = "0.17"
metro = "SV"
Expand Down
59 changes: 44 additions & 15 deletions variables.tf
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
variable "harvester_version" {
type = string
default = "v1.3.1"
description = "Harvester version to be installed"
description = "Harvester version to be installed (Must be a valid version tag from https://github.com/rancherlabs/terraform-harvester-equinix/tree/main/ipxe)"
}

variable "node_count" {
default = "3"
type = number
default = 3
description = "Number of nodes to deploy Harvester cluster"
}

variable "project_name" {
default = ""
description = "Name of the Equinix metal project"
type = string
default = "Harvester Labs"
description = "Name of the Equinix Metal project to deploy into, when not looking up by project_id"
}

variable "metal_create_project" {
Expand All @@ -19,74 +22,100 @@ variable "metal_create_project" {
description = "Create a Metal Project if this is 'true'. Else use provided 'project_name'"
}

variable "organization_id" {
type = string
default = ""
description = "Equinix Metal organization ID to create or find a project in"
}

variable "project_id" {
type = string
default = ""
description = "Equinix Metal project ID to deploy into, if not creating a new project or looking up by name"
}

variable "plan" {
default = "c3.small.x86"
description = "Size of the servers to be deployed on Equinix metal"
type = string
default = "m3.small.x86"
description = "Size of the servers to be deployed on Equinix metal (https://deploy.equinix.com/developers/docs/metal/hardware/standard-servers/)"
}

variable "billing_cycle" {
description = "Equinix metal billing/invoice generation schedule (hourly/daily/monthly/yearly)"
type = string
default = "hourly"
description = "Equinix metal billing/invoice generation schedule"
}

variable "metro" {
type = string
default = "SG"
description = "Equinix metal data center location. Examples: SG,SV,AM,MA,Ny,LA,etc."
description = "Equinix metal data center location (https://deploy.equinix.com/developers/docs/metal/locations/metros/). Examples: SG,SV,AM,MA,Ny,LA,etc."
}

variable "ipxe_script" {
type = string
default = "https://raw.githubusercontent.com/rancherlabs/terraform-harvester-equinix/main/ipxe/ipxe-"
description = "URL for booting the servers with IPXE"
description = "URL to the iPXE script to use for booting the server (harvester_version will be appended to this without the 'v' prefix)"
}

variable "hostname_prefix" {
type = string
default = "harvester-pxe"
description = "Prefix for resources to be created in equinix metal"
}

variable "spot_instance" {
default = false
description = "Set to true to use spot instance instead of on demand. Also set you max bid price if true."
type = bool
default = true
description = "Set to true to use spot instance instead of on demand. Also set your max bid price if true."
}

variable "max_bid_price" {
default = "0.00"
description = "Maximum bid price for spot request."
type = string
default = "0.75"
description = "Maximum bid price for spot request"
}

variable "ssh_key" {
type = string
default = ""
description = "Your ssh key, examples: 'github: myghid' or 'ssh-rsa AAAAblahblah== keyname'"
}

variable "num_of_vlans" {
default = 0
type = number
default = 2
description = "Number of VLANs to be created"
}

variable "rancher_api_url" {
type = string
default = ""
description = "Rancher API endpoint to manager your Harvester cluster"
}

variable "rancher_access_key" {
type = string
default = ""
description = "Rancher access key"
}

variable "rancher_secret_key" {
type = string
default = ""
description = "Rancher secret key"
}

variable "rancher_insecure" {
type = bool
default = false
description = "Allow insecure connections to the Rancher API"
}

variable "api_key" {
type = string
default = ""
description = "Equinix Metal authentication token"
description = "Equinix Metal authentication token. Required when using Spot Instances for HTTP pricing lookups. METAL_AUTH_TOKEN should always be set as an environment variable"
}

variable "use_cheapest_metro" {
Expand Down
Loading