From 0853689d3196adafca896770a3a0084186ffba1f Mon Sep 17 00:00:00 2001 From: Anthony Howe Date: Wed, 24 Jun 2020 13:26:47 -0400 Subject: [PATCH] add ability to specify ssh port and ssh key for controller and vfxt --- .../1.storage/blobstorage/main.tf | 4 + .../1.storage/nfsfiler/main.tf | 11 ++- .../houdinienvironment/3.cache/main.tf | 82 +++++++++++++++---- .../modules/cachewarmer_build/main.tf | 1 + .../modules/cachewarmer_build/variables.tf | 5 ++ .../cachewarmer_manager_install/main.tf | 1 + .../cachewarmer_manager_install/variables.tf | 5 ++ .../modules/cachewarmer_submitjob/main.tf | 1 + .../cachewarmer_submitjob/variables.tf | 5 ++ .../cachewarmer_submitmultiplejobs/main.tf | 1 + .../variables.tf | 5 ++ .../modules/controller/cloud-init.tpl | 4 +- src/terraform/modules/controller/main.tf | 2 +- src/terraform/modules/controller/variables.tf | 5 ++ src/terraform/modules/mount_nfs/main.tf | 1 + src/terraform/modules/mount_nfs/variables.tf | 5 ++ src/terraform/modules/vdbench_config/main.tf | 1 + .../modules/vdbench_config/variables.tf | 5 ++ src/terraform/modules/vmss_config/main.tf | 1 + .../modules/vmss_config/variables.tf | 5 ++ .../terraform-provider-avere/README.md | 2 + .../terraform-provider-avere/averevfxt.go | 6 +- .../terraform-provider-avere/azure.go | 19 ++++- .../terraform-provider-avere/constants.go | 5 ++ .../terraform-provider-avere/resource_vfxt.go | 31 +++++-- .../providers/terraform-provider-avere/ssh.go | 25 +++++- .../terraform-provider-avere/types.go | 2 + 27 files changed, 207 insertions(+), 33 deletions(-) diff --git a/src/terraform/examples/houdinienvironment/1.storage/blobstorage/main.tf b/src/terraform/examples/houdinienvironment/1.storage/blobstorage/main.tf index 610a276cd..041c789fe 100644 --- a/src/terraform/examples/houdinienvironment/1.storage/blobstorage/main.tf +++ b/src/terraform/examples/houdinienvironment/1.storage/blobstorage/main.tf @@ -48,3 +48,7 @@ output "storage_resource_group_name" { output "storage_account_name" { value = "\"${local.storage_account_name}\"" } + +output "use_blob_storage" { + value = true +} diff --git a/src/terraform/examples/houdinienvironment/1.storage/nfsfiler/main.tf b/src/terraform/examples/houdinienvironment/1.storage/nfsfiler/main.tf index 67319df87..df1825134 100644 --- a/src/terraform/examples/houdinienvironment/1.storage/nfsfiler/main.tf +++ b/src/terraform/examples/houdinienvironment/1.storage/nfsfiler/main.tf @@ -10,7 +10,7 @@ locals { vm_ssh_key_data = null //"ssh-rsa AAAAB3...." // nfs filer details - filer_resource_group_name = "houdini_storage_rg" + storage_resource_group_name = "houdini_storage_rg" // more filer sizes listed at https://github.com/Azure/Avere/tree/master/src/terraform/modules/nfs_filer filer_size = "Standard_D2s_v3" @@ -32,7 +32,7 @@ provider "azurerm" { } resource "azurerm_resource_group" "nfsfiler" { - name = local.filer_resource_group_name + name = local.storage_resource_group_name location = local.location } @@ -65,3 +65,10 @@ output "filer_export" { value = "\"${module.nasfiler1.core_filer_export}\"" } +output "storage_resource_group_name" { + value = "\"${local.storage_resource_group_name}\"" +} + +output "use_nfs_storage" { + value = true +} diff --git a/src/terraform/examples/houdinienvironment/3.cache/main.tf b/src/terraform/examples/houdinienvironment/3.cache/main.tf index aae2d9782..16851081e 100644 --- a/src/terraform/examples/houdinienvironment/3.cache/main.tf +++ b/src/terraform/examples/houdinienvironment/3.cache/main.tf @@ -7,6 +7,7 @@ locals { // if you use SSH key, ensure you have ~/.ssh/id_rsa with permission 600 // populated where you are running terraform vm_ssh_key_data = null //"ssh-rsa AAAAB3...." + ssh_port = 22 // vfxt details vfxt_resource_group_name = "houdini_vfxt_rg" @@ -14,8 +15,9 @@ locals { controller_add_public_ip = true vfxt_cluster_name = "vfxt" vfxt_cluster_password = "VFXT_PASSWORD" + vfxt_ssh_key_data = local.vm_ssh_key_data - // replace below variables with the infrastructure variables from 1.base_infrastructure + // replace below variables with the infrastructure variables from 0.network location = "" storage_account_name = "" storage_resource_group_name = "" @@ -25,12 +27,33 @@ locals { vnet_render_clients1_subnet_id = "" vnet_resource_group = "" + // either replace below variables from + // 1.storage/blobstorage, + use_blob_storage = false + storage_account_name = "" + //storage_resource_group_name = "" + // or 1.storage/nfsfiler + use_nfs_storage = false + filer_address = "" + filer_export = "" + storage_resource_group_name = "" + // advanced scenarios: the variables below raraly need changing // in addition to storage account put the custom image resource group here alternative_resource_groups = [local.storage_resource_group_name] // cloud filer details - junction_namespace_path = "/storagevfxt" + junction_namespace_path_clfs = "/houdiniclfs" + junction_namespace_path_filer = "/houdinifiler" + // only for the blob storage storage_container_name = "cache" + // only for the nfs filer storage + // vfxt cache polies + // "Clients Bypassing the Cluster" + // "Read Caching" + // "Read and Write Caching" + // "Full Caching" + // "Transitioning Clients Before or After a Migration" + cache_policy = "Clients Bypassing the Cluster" } provider "azurerm" { @@ -48,6 +71,7 @@ module "vfxtcontroller" { ssh_key_data = local.vm_ssh_key_data add_public_ip = local.controller_add_public_ip alternative_resource_groups = local.alternative_resource_groups + ssh_port = local.ssh_port // network details virtual_network_resource_group = local.vnet_resource_group @@ -61,10 +85,11 @@ resource "avere_vfxt" "vfxt" { controller_admin_username = module.vfxtcontroller.controller_username // ssh key takes precedence over controller password controller_admin_password = local.vm_ssh_key_data != null && local.vm_ssh_key_data != "" ? "" : local.vm_admin_password + controller_ssh_port = local.ssh_port // terraform is not creating the implicit dependency on the controller module // otherwise during destroy, it tries to destroy the controller at the same time as vfxt cluster // to work around, add the explicit dependency - depends_on = [module.vfxtcontroller] + depends_on = [module.vfxtcontroller.module_depends_on_id] // network azure_network_resource_group = local.vnet_resource_group @@ -75,6 +100,7 @@ resource "avere_vfxt" "vfxt" { azure_resource_group = local.vfxt_resource_group_name vfxt_cluster_name = local.vfxt_cluster_name vfxt_admin_password = local.vfxt_cluster_password + vfxt_ssh_key_data = local.vfxt_ssh_key_data vfxt_node_count = 3 global_custom_settings = [ @@ -85,17 +111,40 @@ resource "avere_vfxt" "vfxt" { "cluster.NfsFrontEndCwnd EK 1", ] - azure_storage_filer { - account_name = local.storage_account_name - container_name = local.storage_container_name - junction_namespace_path = local.junction_namespace_path - custom_settings = [ - "client_rt_preferred FE 524288", - "client_wt_preferred NO 524288", - "nfsConnMult YW 20", - "autoWanOptimize YF 2", - "always_forward OZ 1", - ] + dynamic "azure_storage_filer" { + for_each = local.use_blob_storage ? ["use_blob_storage"] : [] + content { + account_name = local.storage_account_name + container_name = local.storage_container_name + junction_namespace_path = local.junction_namespace_path_clfs + custom_settings = [ + "client_rt_preferred FE 524288", + "client_wt_preferred NO 524288", + "nfsConnMult YW 20", + "autoWanOptimize YF 2", + "always_forward OZ 1", + ] + } + } + + dynamic "core_filer" { + for_each = local.use_nfs_storage ? ["use_nfs_storage"] : [] + content { + name = "nfs1" + fqdn_or_primary_ip = local.filer_address + cache_policy = local.cache_policy + custom_settings = [ + "client_rt_preferred FE 524288", + "client_wt_preferred NO 524288", + "nfsConnMult YW 20", + "autoWanOptimize YF 2", + "always_forward OZ 1", + ] + junction { + namespace_path = local.junction_namespace_path_filer + core_filer_export = local.filer_export + } + } } } @@ -105,10 +154,11 @@ module "mount_nfs" { node_address = module.vfxtcontroller.controller_address admin_username = local.vm_admin_username admin_password = local.vm_admin_password + ssh_port = local.ssh_port ssh_key_data = local.vm_ssh_key_data mount_dir = "/mnt/nfs" nfs_address = tolist(avere_vfxt.vfxt.vserver_ip_addresses)[0] - nfs_export_path = local.junction_namespace_path + nfs_export_path = local.use_nfs_storage ? local.junction_namespace_path_filer : local.junction_namespace_path_clfs } output "controller_username" { @@ -132,5 +182,5 @@ output "mount_addresses" { } output "mount_path" { - value = "\"${local.junction_namespace_path}\"" + value = "\"${local.use_nfs_storage ? local.junction_namespace_path_filer : local.junction_namespace_path_clfs}\"" } \ No newline at end of file diff --git a/src/terraform/modules/cachewarmer_build/main.tf b/src/terraform/modules/cachewarmer_build/main.tf index b82b47aa3..25e25b463 100644 --- a/src/terraform/modules/cachewarmer_build/main.tf +++ b/src/terraform/modules/cachewarmer_build/main.tf @@ -8,6 +8,7 @@ locals { resource "null_resource" "build_cachewarmer_bootstrap" { connection { type = "ssh" + port = var.ssh_port host = var.node_address user = var.admin_username password = var.ssh_key_data != null && var.ssh_key_data != "" ? "" : var.admin_password diff --git a/src/terraform/modules/cachewarmer_build/variables.tf b/src/terraform/modules/cachewarmer_build/variables.tf index bb993c024..095ce2452 100644 --- a/src/terraform/modules/cachewarmer_build/variables.tf +++ b/src/terraform/modules/cachewarmer_build/variables.tf @@ -16,6 +16,11 @@ variable "ssh_key_data" { description = "(optional) The public SSH key used for access to the controller or jumpbox. If not specified, the password needs to be set. The ssh_key_data takes precedence over the password, and if set, the password will be ignored." } +variable "ssh_port" { + description = "specifies the tcp port to use for ssh" + default = 22 +} + variable "bootstrap_mount_address" { description = "the mount address that hosts the worker bootstrap script" } diff --git a/src/terraform/modules/cachewarmer_manager_install/main.tf b/src/terraform/modules/cachewarmer_manager_install/main.tf index 89f8a10ca..b8b7d5f6d 100644 --- a/src/terraform/modules/cachewarmer_manager_install/main.tf +++ b/src/terraform/modules/cachewarmer_manager_install/main.tf @@ -11,6 +11,7 @@ locals { resource "null_resource" "install_cachewarmer_manager" { connection { type = "ssh" + port = var.ssh_port host = var.node_address user = var.admin_username password = var.ssh_key_data != null && var.ssh_key_data != "" ? "" : var.admin_password diff --git a/src/terraform/modules/cachewarmer_manager_install/variables.tf b/src/terraform/modules/cachewarmer_manager_install/variables.tf index 42d4ff692..a08f2e906 100644 --- a/src/terraform/modules/cachewarmer_manager_install/variables.tf +++ b/src/terraform/modules/cachewarmer_manager_install/variables.tf @@ -16,6 +16,11 @@ variable "ssh_key_data" { description = "(optional) The public SSH key used for access to the controller or jumpbox. If not specified, the password needs to be set. The ssh_key_data takes precedence over the password, and if set, the password will be ignored." } +variable "ssh_port" { + description = "specifies the tcp port to use for ssh" + default = 22 +} + variable "bootstrap_mount_address" { description = "the mount address that hosts the manager and worker bootstrap script" } diff --git a/src/terraform/modules/cachewarmer_submitjob/main.tf b/src/terraform/modules/cachewarmer_submitjob/main.tf index d53b0d702..b593bf243 100644 --- a/src/terraform/modules/cachewarmer_submitjob/main.tf +++ b/src/terraform/modules/cachewarmer_submitjob/main.tf @@ -6,6 +6,7 @@ locals { resource "null_resource" "cachewarmer_submitjob" { connection { type = "ssh" + port = var.ssh_port host = var.node_address user = var.admin_username password = var.ssh_key_data != null && var.ssh_key_data != "" ? "" : var.admin_password diff --git a/src/terraform/modules/cachewarmer_submitjob/variables.tf b/src/terraform/modules/cachewarmer_submitjob/variables.tf index 7fbac3540..77956202b 100644 --- a/src/terraform/modules/cachewarmer_submitjob/variables.tf +++ b/src/terraform/modules/cachewarmer_submitjob/variables.tf @@ -16,6 +16,11 @@ variable "ssh_key_data" { description = "(optional) The public SSH key used for access to the controller or jumpbox. If not specified, the password needs to be set. The ssh_key_data takes precedence over the password, and if set, the password will be ignored." } +variable "ssh_port" { + description = "specifies the tcp port to use for ssh" + default = 22 +} + variable "jobMount_address" { description = "the mount address for warm job processing" } diff --git a/src/terraform/modules/cachewarmer_submitmultiplejobs/main.tf b/src/terraform/modules/cachewarmer_submitmultiplejobs/main.tf index 5a8aeea06..e65e7b392 100644 --- a/src/terraform/modules/cachewarmer_submitmultiplejobs/main.tf +++ b/src/terraform/modules/cachewarmer_submitmultiplejobs/main.tf @@ -10,6 +10,7 @@ resource "null_resource" "cachewarmer_submitmultiplejobs" { connection { type = "ssh" + port = var.ssh_port host = var.node_address user = var.admin_username password = var.ssh_key_data != null && var.ssh_key_data != "" ? "" : var.admin_password diff --git a/src/terraform/modules/cachewarmer_submitmultiplejobs/variables.tf b/src/terraform/modules/cachewarmer_submitmultiplejobs/variables.tf index 0c4047a6b..5ddd4ff7b 100644 --- a/src/terraform/modules/cachewarmer_submitmultiplejobs/variables.tf +++ b/src/terraform/modules/cachewarmer_submitmultiplejobs/variables.tf @@ -16,6 +16,11 @@ variable "ssh_key_data" { description = "(optional) The public SSH key used for access to the controller or jumpbox. If not specified, the password needs to be set. The ssh_key_data takes precedence over the password, and if set, the password will be ignored." } +variable "ssh_port" { + description = "specifies the tcp port to use for ssh" + default = 22 +} + variable "jobMount_address" { description = "the mount address for warm job processing" } diff --git a/src/terraform/modules/controller/cloud-init.tpl b/src/terraform/modules/controller/cloud-init.tpl index 375cd51ab..a2e12526b 100644 --- a/src/terraform/modules/controller/cloud-init.tpl +++ b/src/terraform/modules/controller/cloud-init.tpl @@ -15,4 +15,6 @@ write_files: permissions: '0755' runcmd: - - patch --quiet --forward /usr/local/lib/python2.7/dist-packages/vFXT/msazure.py /usr/local/lib/python2.7/dist-packages/vFXT/msazure.py.patch1 \ No newline at end of file + - set -x + - patch --quiet --forward /usr/local/lib/python2.7/dist-packages/vFXT/msazure.py /usr/local/lib/python2.7/dist-packages/vFXT/msazure.py.patch1 + - if [ "${ssh_port}" -ne "22" ]; then sed -i 's/^#\?Port .*/Port ${ssh_port}/' /etc/ssh/sshd_config && systemctl restart sshd ; fi diff --git a/src/terraform/modules/controller/main.tf b/src/terraform/modules/controller/main.tf index 492e97d44..48bb85a89 100644 --- a/src/terraform/modules/controller/main.tf +++ b/src/terraform/modules/controller/main.tf @@ -12,7 +12,7 @@ locals { # send the script file to custom data, adding env vars script_file_b64 = base64gzip(replace(file("${path.module}/averecmd.txt"),"\r","")) msazure_patch1_file_b64 = base64gzip(replace(file("${path.module}/msazure.py.patch1"),"\r","")) - cloud_init_file = templatefile("${path.module}/cloud-init.tpl", { averecmd = local.script_file_b64, msazure_patch1 = local.msazure_patch1_file_b64 }) + cloud_init_file = templatefile("${path.module}/cloud-init.tpl", { averecmd = local.script_file_b64, msazure_patch1 = local.msazure_patch1_file_b64, ssh_port = var.ssh_port }) # the roles assigned to the controller managed identity principal # the contributor role is required to create Avere clusters avere_create_cluster_role = "Avere Contributor" diff --git a/src/terraform/modules/controller/variables.tf b/src/terraform/modules/controller/variables.tf index d7b6fef68..7897563a8 100644 --- a/src/terraform/modules/controller/variables.tf +++ b/src/terraform/modules/controller/variables.tf @@ -67,6 +67,11 @@ variable "apply_patch" { default = true } +variable "ssh_port" { + description = "specifies the tcp port to use for ssh" + default = 22 +} + variable "module_depends_on" { default = [""] description = "depends on workaround discussed in https://discuss.hashicorp.com/t/tips-howto-implement-module-depends-on-emulation/2305/2" diff --git a/src/terraform/modules/mount_nfs/main.tf b/src/terraform/modules/mount_nfs/main.tf index 34a7c48ee..88e3dae00 100644 --- a/src/terraform/modules/mount_nfs/main.tf +++ b/src/terraform/modules/mount_nfs/main.tf @@ -7,6 +7,7 @@ resource "null_resource" "install_bootstrap" { # So we just choose the first in this case connection { type = "ssh" + port = var.ssh_port host = var.node_address user = var.admin_username password = var.ssh_key_data != null && var.ssh_key_data != "" ? "" : var.admin_password diff --git a/src/terraform/modules/mount_nfs/variables.tf b/src/terraform/modules/mount_nfs/variables.tf index ba538fd76..7d71e3621 100644 --- a/src/terraform/modules/mount_nfs/variables.tf +++ b/src/terraform/modules/mount_nfs/variables.tf @@ -16,6 +16,11 @@ variable "ssh_key_data" { description = "(optional) The public SSH key used for access to the controller or jumpbox. If not specified, the password needs to be set. The ssh_key_data takes precedence over the password, and if set, the password will be ignored." } +variable "ssh_port" { + description = "specifies the tcp port to use for ssh" + default = 22 +} + variable "mount_dir" { description = "the mount directory on the local machine" default = "/mnt/nfs" diff --git a/src/terraform/modules/vdbench_config/main.tf b/src/terraform/modules/vdbench_config/main.tf index 6459d0ee5..c420a565a 100644 --- a/src/terraform/modules/vdbench_config/main.tf +++ b/src/terraform/modules/vdbench_config/main.tf @@ -8,6 +8,7 @@ resource "null_resource" "install_vdbench_bootstrap" { # So we just choose the first in this case connection { type = "ssh" + port = var.ssh_port host = var.node_address user = var.admin_username password = var.ssh_key_data != null && var.ssh_key_data != "" ? "" : var.admin_password diff --git a/src/terraform/modules/vdbench_config/variables.tf b/src/terraform/modules/vdbench_config/variables.tf index d51f02e93..2a6a1028d 100644 --- a/src/terraform/modules/vdbench_config/variables.tf +++ b/src/terraform/modules/vdbench_config/variables.tf @@ -15,6 +15,11 @@ variable "ssh_key_data" { description = "(optional) The public SSH key used for access to the controller or jumpbox. If not specified, the password needs to be set. The ssh_key_data takes precedence over the password, and if set, the password will be ignored." } +variable "ssh_port" { + description = "specifies the tcp port to use for ssh" + default = 22 +} + variable "nfs_address" { description = "the private name or ip address of the nfs server" } diff --git a/src/terraform/modules/vmss_config/main.tf b/src/terraform/modules/vmss_config/main.tf index be46e0191..37d183b46 100644 --- a/src/terraform/modules/vmss_config/main.tf +++ b/src/terraform/modules/vmss_config/main.tf @@ -8,6 +8,7 @@ resource "null_resource" "install_bootstrap" { # So we just choose the first in this case connection { type = "ssh" + port = var.ssh_port host = var.node_address user = var.admin_username password = var.ssh_key_data != null && var.ssh_key_data != "" ? "" : var.admin_password diff --git a/src/terraform/modules/vmss_config/variables.tf b/src/terraform/modules/vmss_config/variables.tf index 57ef26bb4..c45a495d7 100644 --- a/src/terraform/modules/vmss_config/variables.tf +++ b/src/terraform/modules/vmss_config/variables.tf @@ -16,6 +16,11 @@ variable "ssh_key_data" { description = "(optional) The public SSH key used for access to the controller or jumpbox. If not specified, the password needs to be set. The ssh_key_data takes precedence over the password, and if set, the password will be ignored." } +variable "ssh_port" { + description = "specifies the tcp port to use for ssh" + default = 22 +} + variable "nfs_address" { description = "the private name or ip address of the nfs server" } diff --git a/src/terraform/providers/terraform-provider-avere/README.md b/src/terraform/providers/terraform-provider-avere/README.md index 40695c3c1..fa49f8d40 100644 --- a/src/terraform/providers/terraform-provider-avere/README.md +++ b/src/terraform/providers/terraform-provider-avere/README.md @@ -74,6 +74,7 @@ The following arguments are supported: * [controller_address](#controller_address) - (Optional if [run_local](#run_local) is set to true) the ip address of the controller. This address may be public or private. If private it will need to be reachable from where terraform is executed. * [controller_admin_username](#controller_admin_username) - (Optional if [run_local](#run_local) is set to true) the admin username to the controller * [controller_admin_password](#controller_admin_password) - (Optional) only specify if [run_local](#run_local) is set to false and password is to be used to access the key, instead of the ssh key ~/.ssh/id_rsa +* [controller_ssh_port](#controller_ssh_port) - (Optional) only specify if [run_local](#run_local) is set to false and the ssh is a value other than the default port 22. * [run_local](#run_local) - (Optional) specifies if terraform is run directly on the controller (or similar machine with vfxt.py, az cli, and averecmd). This defaults to false, and if false, a minimum of [controller_address](#controller_address) and [controller_admin_username](#controller_admin_username) must be set. * [run_local](#run_local) - (Optional) non-ascii characters can break deployment so this is set to `false` by default. In more advanced scenarios, the ascii check may be disabled by setting to `true`. * [location](#location) - (Required) specify the azure region. Note: cluster re-created if modified. @@ -91,6 +92,7 @@ The following arguments are supported: * [image_id](#image_id) - (Optional) specify a custom image id for the vFXT. This is useful when needing to use a bug fix or there is a marketplace outage. For more information see the [docs on how to create a custom image for the conroller and vfxt](../../examples/vfxt#create-vfxt-controller-from-custom-images). Note: cluster re-created if modified. * [vfxt_cluster_name](#vfxt_cluster_name) - (Required) this is the name of the vFXT cluster that is shown when you browse to the management ip. To help Avere support, choose a name that matches the Avere's purpose. Note: cluster re-created if modified. * [vfxt_admin_password](#vfxt_admin_password) - (Required) the password for the vFXT cluster. Note: cluster re-created if modified. +* [vfxt_ssh_key_data](#vfxt_ssh_key_data) - (Optional) deploy the cluster using the ssh public key for authentication instead of the password, this is useful to align with policies. * [vfxt_node_count](#vfxt_node_count) - (Required) the number of nodes to deploy for the Avere cluster. The count may be a minimum of 3 and a maximum of 16. If the cluster is already deployed, this will result in scaling up or down to the node count. It requires about 15 minutes to delete and add each node in a scale-up or scale-down scenario. * [node_cache_size](#node_cache_size) - (Optional) The cache size in GB to use for each Avere vFXT VM. There are two options: 1024 or 4096 where 4096 is the default value. Note: cluster re-created if modified. * [vserver_first_ip](#vserver_first_ip) - (Optional) To ensure predictable vserver ranges for dns pre-population, specify the first IP of the vserver. This will create consecutive ip addresses based on the node count set in [vfxt_node_count](#vfxt_node_count). The following configuration is recommended: diff --git a/src/terraform/providers/terraform-provider-avere/averevfxt.go b/src/terraform/providers/terraform-provider-avere/averevfxt.go index 951765f49..5657a7cc1 100644 --- a/src/terraform/providers/terraform-provider-avere/averevfxt.go +++ b/src/terraform/providers/terraform-provider-avere/averevfxt.go @@ -44,11 +44,13 @@ func NewAvereVfxt( controllerAddress string, controllerUsername string, sshAuthMethod ssh.AuthMethod, + sshPort int, runLocal bool, allowNonAscii bool, platform IaasPlatform, avereVfxtName string, avereAdminPassword string, + sshKeyData string, enableSupportUploads bool, nodeCount int, nodeSize string, @@ -70,11 +72,13 @@ func NewAvereVfxt( ControllerAddress: controllerAddress, ControllerUsename: controllerUsername, SshAuthMethod: sshAuthMethod, + SshPort: sshPort, RunLocal: runLocal, AllowNonAscii: allowNonAscii, Platform: platform, AvereVfxtName: avereVfxtName, AvereAdminPassword: avereAdminPassword, + AvereSshKeyData: sshKeyData, EnableSupportUploads: enableSupportUploads, NodeCount: nodeCount, NodeSize: nodeSize, @@ -107,7 +111,7 @@ func (a *AvereVfxt) RunCommand(cmd string) (bytes.Buffer, bytes.Buffer, error) { if a.RunLocal { return BashCommand(cmd) } else { - return SSHCommand(a.ControllerAddress, a.ControllerUsename, a.SshAuthMethod, cmd) + return SSHCommand(a.ControllerAddress, a.ControllerUsename, a.SshAuthMethod, cmd, a.SshPort) } } diff --git a/src/terraform/providers/terraform-provider-avere/azure.go b/src/terraform/providers/terraform-provider-avere/azure.go index 35094bf7d..fa3cc70c0 100644 --- a/src/terraform/providers/terraform-provider-avere/azure.go +++ b/src/terraform/providers/terraform-provider-avere/azure.go @@ -68,6 +68,15 @@ func (a Azure) CreateVfxt(avereVfxt *AvereVfxt) error { if err := VerifyAzLogin(avereVfxt); err != nil { return fmt.Errorf("Error verifying az cli login: %v", err) } + if len(avereVfxt.AvereSshKeyData) > 0 { + cmd := a.getEnsureAvereSshKeyData(avereVfxt.AvereSshKeyData) + stdoutBuf, stderrBuf, err := avereVfxt.RunCommand(cmd) + if err != nil { + allErrors := getAllVfxtErrors(stdoutBuf, stderrBuf) + return fmt.Errorf("Error ensuring public key: %v, '%s'", err, allErrors) + } + } + cmd := a.getCreateVfxtCommand(avereVfxt) stdoutBuf, stderrBuf, err := avereVfxt.RunCommand(cmd) if err != nil { @@ -239,6 +248,10 @@ func VerifyAzLogin(avereVfxt *AvereVfxt) error { return err } +func (a Azure) getEnsureAvereSshKeyData(publicKeyData string) string { + return WrapCommandForLogging(fmt.Sprintf("echo '%s' > %s", publicKeyData, VfxtKeyPubFile), ShellLogFile) +} + func (a Azure) getCreateVfxtCommand(avereVfxt *AvereVfxt) string { vServerStr := "" if len(avereVfxt.FirstIPAddress) > 0 && len(avereVfxt.FirstIPAddress) > 0 { @@ -292,10 +305,14 @@ func (a Azure) getBaseVfxtCommand(avereVfxt *AvereVfxt) string { // add the vfxt information sb.WriteString(fmt.Sprintf("--cluster-name %s --admin-password '%s' ", avereVfxt.AvereVfxtName, avereVfxt.AvereAdminPassword)) + if len(avereVfxt.AvereSshKeyData) > 0 { + sb.WriteString(fmt.Sprintf("--ssh-key %s ", VfxtKeyPubFile)) + } + return sb.String() } -// used when mulitple commands piped together +// used when multiple commands piped together func getAzCliProxyExports(proxyUri string) string { if len(proxyUri) > 0 { return fmt.Sprintf(" export HTTPS_PROXY=\"%s\" && export NO_PROXY=\"169.254.169.254\" && ", proxyUri) diff --git a/src/terraform/providers/terraform-provider-avere/constants.go b/src/terraform/providers/terraform-provider-avere/constants.go index a3dbf830a..9ec437426 100644 --- a/src/terraform/providers/terraform-provider-avere/constants.go +++ b/src/terraform/providers/terraform-provider-avere/constants.go @@ -6,12 +6,15 @@ const ( AvereAdminUsername = "admin" MinNodesCount = 3 MaxNodesCount = 16 + DefaultSshPort = 22 VfxtLogDateFormat = "2006-01-02.15.04.05" VServerRangeSeperator = "-" AverecmdRetryCount = 30 // wait 5 minutes (ex. remove core filer gets perm denied for a while) AverecmdRetrySleepSeconds = 10 AverecmdLogFile = "~/averecmd.log" VServerName = "vserver" + VfxtKeyPubFile = "~/vfxt_ssh_key_data.pub" + ShellLogFile = "~/shell.log" // Platform PlatformAzure = "azure" @@ -82,6 +85,7 @@ const ( controller_address = "controller_address" controller_admin_username = "controller_admin_username" controller_admin_password = "controller_admin_password" + controller_ssh_port = "controller_ssh_port" run_local = "run_local" allow_non_ascii = "allow_non_ascii" location = "location" @@ -100,6 +104,7 @@ const ( image_id = "image_id" vfxt_cluster_name = "vfxt_cluster_name" vfxt_admin_password = "vfxt_admin_password" + vfxt_ssh_key_data = "vfxt_ssh_key_data" vfxt_node_count = "vfxt_node_count" node_size = "node_size" node_cache_size = "node_cache_size" diff --git a/src/terraform/providers/terraform-provider-avere/resource_vfxt.go b/src/terraform/providers/terraform-provider-avere/resource_vfxt.go index 22f74b0e0..09d896b19 100644 --- a/src/terraform/providers/terraform-provider-avere/resource_vfxt.go +++ b/src/terraform/providers/terraform-provider-avere/resource_vfxt.go @@ -41,6 +41,11 @@ func resourceVfxt() *schema.Resource { Optional: true, Sensitive: true, }, + controller_ssh_port: { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(0, 65535), + }, run_local: { Type: schema.TypeBool, Optional: true, @@ -145,10 +150,16 @@ func resourceVfxt() *schema.Resource { Sensitive: true, ValidateFunc: validation.StringDoesNotContainAny(" '\""), }, + vfxt_ssh_key_data: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringDoesNotContainAny("'\""), + }, vfxt_node_count: { Type: schema.TypeInt, Required: true, - ValidateFunc: validation.IntBetween(3, 16), + ValidateFunc: validation.IntBetween(MinNodesCount, MaxNodesCount), }, node_size: { Type: schema.TypeString, @@ -360,7 +371,7 @@ func resourceVfxtCreate(d *schema.ResourceData, m interface{}) error { } if avereVfxt.RunLocal == false { - if err := VerifySSHConnection(avereVfxt.ControllerAddress, avereVfxt.ControllerUsename, avereVfxt.SshAuthMethod); err != nil { + if err := VerifySSHConnection(avereVfxt.ControllerAddress, avereVfxt.ControllerUsename, avereVfxt.SshAuthMethod, avereVfxt.SshPort); err != nil { return err } } @@ -464,7 +475,7 @@ func resourceVfxtRead(d *schema.ResourceData, m interface{}) error { } if avereVfxt.RunLocal == false { - if err := VerifySSHConnection(avereVfxt.ControllerAddress, avereVfxt.ControllerUsename, avereVfxt.SshAuthMethod); err != nil { + if err := VerifySSHConnection(avereVfxt.ControllerAddress, avereVfxt.ControllerUsename, avereVfxt.SshAuthMethod, avereVfxt.SshPort); err != nil { return err } } @@ -498,7 +509,7 @@ func resourceVfxtUpdate(d *schema.ResourceData, m interface{}) error { } if avereVfxt.RunLocal == false { - if err := VerifySSHConnection(avereVfxt.ControllerAddress, avereVfxt.ControllerUsename, avereVfxt.SshAuthMethod); err != nil { + if err := VerifySSHConnection(avereVfxt.ControllerAddress, avereVfxt.ControllerUsename, avereVfxt.SshAuthMethod, avereVfxt.SshPort); err != nil { return err } } @@ -632,7 +643,7 @@ func resourceVfxtDelete(d *schema.ResourceData, m interface{}) error { } if avereVfxt.RunLocal == false { - if err := VerifySSHConnection(avereVfxt.ControllerAddress, avereVfxt.ControllerUsename, avereVfxt.SshAuthMethod); err != nil { + if err := VerifySSHConnection(avereVfxt.ControllerAddress, avereVfxt.ControllerUsename, avereVfxt.SshAuthMethod, avereVfxt.SshPort); err != nil { return err } } @@ -654,6 +665,7 @@ func resourceVfxtDelete(d *schema.ResourceData, m interface{}) error { func fillAvereVfxt(d *schema.ResourceData) (*AvereVfxt, error) { var err error var controllerAddress, controllerAdminUsername, controllerAdminPassword string + var controllerSshPort int runLocal := d.Get(run_local).(bool) allowNonAscii := d.Get(allow_non_ascii).(bool) @@ -676,8 +688,10 @@ func fillAvereVfxt(d *schema.ResourceData) (*AvereVfxt, error) { } else { return nil, fmt.Errorf("missing argument '%s'", controller_admin_username) } - if v, exists := d.GetOk(controller_admin_password); exists { - controllerAdminPassword = v.(string) + if v, exists := d.GetOk(controller_ssh_port); exists { + controllerSshPort = v.(int) + } else { + controllerSshPort = DefaultSshPort } if len(controllerAdminPassword) > 0 { @@ -722,11 +736,13 @@ func fillAvereVfxt(d *schema.ResourceData) (*AvereVfxt, error) { controllerAddress, controllerAdminUsername, authMethod, + controllerSshPort, runLocal, allowNonAscii, iaasPlatform, d.Get(vfxt_cluster_name).(string), d.Get(vfxt_admin_password).(string), + d.Get(vfxt_ssh_key_data).(string), d.Get(enable_support_uploads).(bool), nodeCount, d.Get(node_size).(string), @@ -1365,6 +1381,7 @@ func validateSchemaforOnlyAscii(d *schema.ResourceData) error { image_id, vfxt_cluster_name, vfxt_admin_password, + vfxt_ssh_key_data, } for _, parameter := range validateParameterSlice { diff --git a/src/terraform/providers/terraform-provider-avere/ssh.go b/src/terraform/providers/terraform-provider-avere/ssh.go index 84361bc86..7682cbdf7 100644 --- a/src/terraform/providers/terraform-provider-avere/ssh.go +++ b/src/terraform/providers/terraform-provider-avere/ssh.go @@ -39,11 +39,28 @@ func GetKeyFileAuthMethod() (authMethod ssh.AuthMethod, err error) { return } +func GetPublicKeyPubString() (string, error) { + usr, _ := osuser.Current() + file := usr.HomeDir + "/.ssh/id_rsa" + buf, err := ioutil.ReadFile(file) + if err != nil { + return "", err + } + key, err := ssh.ParsePrivateKey(buf) + if err != nil { + return "", err + } + + pubKeyBytes := ssh.MarshalAuthorizedKey(key.PublicKey()) + + return string(pubKeyBytes), nil +} + // on poor wi-fi connections it can take multiple attempts for the first connection -func VerifySSHConnection(host string, username string, authMethod ssh.AuthMethod) error { +func VerifySSHConnection(host string, username string, authMethod ssh.AuthMethod, port int) error { var err error for retries := 0; retries < SSHVerifyRetryCount; retries++ { - if _, _, err = SSHCommand(host, username, authMethod, VerifyCommand); err == nil { + if _, _, err = SSHCommand(host, username, authMethod, VerifyCommand, port); err == nil { // success return nil } @@ -53,7 +70,7 @@ func VerifySSHConnection(host string, username string, authMethod ssh.AuthMethod } // SSHCommand runs an ssh command, and captures the stdout and stderr in two byte buffers -func SSHCommand(host string, username string, authMethod ssh.AuthMethod, cmd string) (bytes.Buffer, bytes.Buffer, error) { +func SSHCommand(host string, username string, authMethod ssh.AuthMethod, cmd string, port int) (bytes.Buffer, bytes.Buffer, error) { var stdoutBuf, stderrBuf bytes.Buffer sshConfig := &ssh.ClientConfig{ @@ -63,7 +80,7 @@ func SSHCommand(host string, username string, authMethod ssh.AuthMethod, cmd str }, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } - connection, err := ssh.Dial("tcp", fmt.Sprintf("%s:22", host), sshConfig) + connection, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", host, port), sshConfig) if err != nil { return stdoutBuf, stderrBuf, fmt.Errorf("failed to create connection: %s", err) } diff --git a/src/terraform/providers/terraform-provider-avere/types.go b/src/terraform/providers/terraform-provider-avere/types.go index 8578c7c0b..e997ab3d8 100644 --- a/src/terraform/providers/terraform-provider-avere/types.go +++ b/src/terraform/providers/terraform-provider-avere/types.go @@ -20,6 +20,7 @@ type AvereVfxt struct { ControllerUsename string SshAuthMethod ssh.AuthMethod + SshPort int RunLocal bool AllowNonAscii bool @@ -28,6 +29,7 @@ type AvereVfxt struct { AvereVfxtName string AvereAdminPassword string + AvereSshKeyData string EnableSupportUploads bool NodeCount int NodeSize string