diff --git a/cli/internal/cloudcmd/create.go b/cli/internal/cloudcmd/create.go index e63c8139e..4f7c1c157 100644 --- a/cli/internal/cloudcmd/create.go +++ b/cli/internal/cloudcmd/create.go @@ -272,14 +272,16 @@ func (c *Creator) createOpenStack(ctx context.Context, cl terraformClient, confi CountWorkers: workerCount, StateDiskSizeGB: config.StateDiskSizeGB, }, - Cloud: config.Provider.OpenStack.Cloud, - AvailabilityZone: config.Provider.OpenStack.AvailabilityZone, - FloatingIPPoolID: config.Provider.OpenStack.FloatingIPPoolID, - FlavorID: config.Provider.OpenStack.FlavorID, - ImageURL: image, - DirectDownload: *config.Provider.OpenStack.DirectDownload, - OpenStackServiceAccountToken: config.Provider.OpenStack.ServiceAccountToken, - Debug: config.IsDebugCluster(), + Cloud: config.Provider.OpenStack.Cloud, + AvailabilityZone: config.Provider.OpenStack.AvailabilityZone, + FloatingIPPoolID: config.Provider.OpenStack.FloatingIPPoolID, + FlavorID: config.Provider.OpenStack.FlavorID, + ImageURL: image, + DirectDownload: *config.Provider.OpenStack.DirectDownload, + OpenstackUserDomainName: config.Provider.OpenStack.UserDomainName, + OpenstackUsername: config.Provider.OpenStack.Username, + OpenstackPassword: config.Provider.OpenStack.Password, + Debug: config.IsDebugCluster(), } if err := cl.PrepareWorkspace(path.Join("terraform", strings.ToLower(cloudprovider.OpenStack.String())), &vars); err != nil { diff --git a/cli/internal/terraform/terraform/openstack/main.tf b/cli/internal/terraform/terraform/openstack/main.tf index 0ba5595fb..30d1daf57 100644 --- a/cli/internal/terraform/terraform/openstack/main.tf +++ b/cli/internal/terraform/terraform/openstack/main.tf @@ -40,7 +40,7 @@ locals { ][0] identity_endpoint = [ for endpoint in local.identity_service.endpoints : - endpoint if(endpoint.interface == "internal") + endpoint if(endpoint.interface == "public") ][0] identity_internal_url = local.identity_endpoint.url } @@ -138,43 +138,43 @@ resource "openstack_compute_secgroup_v2" "vpc_secgroup" { } module "instance_group_control_plane" { - source = "./modules/instance_group" - name = local.name - role = "ControlPlane" - instance_count = var.control_plane_count - image_id = openstack_images_image_v2.constellation_os_image.image_id - flavor_id = var.flavor_id - security_groups = [ - openstack_compute_secgroup_v2.vpc_secgroup.id, - ] - tags = local.tags - uid = local.uid - disk_size = var.state_disk_size - availability_zone = var.availability_zone - network_id = openstack_networking_network_v2.vpc_network.id - init_secret_hash = local.initSecretHash - identity_internal_url = local.identity_internal_url - openstack_service_account_token = var.openstack_service_account_token + source = "./modules/instance_group" + name = local.name + role = "ControlPlane" + instance_count = var.control_plane_count + image_id = openstack_images_image_v2.constellation_os_image.image_id + flavor_id = var.flavor_id + security_groups = [openstack_compute_secgroup_v2.vpc_secgroup.id] + tags = local.tags + uid = local.uid + disk_size = var.state_disk_size + availability_zone = var.availability_zone + network_id = openstack_networking_network_v2.vpc_network.id + init_secret_hash = local.initSecretHash + identity_internal_url = local.identity_internal_url + openstack_username = var.openstack_username + openstack_password = var.openstack_password + openstack_user_domain_name = var.openstack_user_domain_name } module "instance_group_worker" { - source = "./modules/instance_group" - name = local.name - role = "Worker" - instance_count = var.worker_count - image_id = openstack_images_image_v2.constellation_os_image.image_id - flavor_id = var.flavor_id - tags = local.tags - uid = local.uid - security_groups = [ - openstack_compute_secgroup_v2.vpc_secgroup.id, - ] - disk_size = var.state_disk_size - availability_zone = var.availability_zone - network_id = openstack_networking_network_v2.vpc_network.id - init_secret_hash = local.initSecretHash - identity_internal_url = local.identity_internal_url - openstack_service_account_token = var.openstack_service_account_token + source = "./modules/instance_group" + name = local.name + role = "Worker" + instance_count = var.worker_count + image_id = openstack_images_image_v2.constellation_os_image.image_id + flavor_id = var.flavor_id + tags = local.tags + uid = local.uid + security_groups = [openstack_compute_secgroup_v2.vpc_secgroup.id] + disk_size = var.state_disk_size + availability_zone = var.availability_zone + network_id = openstack_networking_network_v2.vpc_network.id + init_secret_hash = local.initSecretHash + identity_internal_url = local.identity_internal_url + openstack_username = var.openstack_username + openstack_password = var.openstack_password + openstack_user_domain_name = var.openstack_user_domain_name } resource "openstack_networking_floatingip_v2" "public_ip" { diff --git a/cli/internal/terraform/terraform/openstack/modules/instance_group/main.tf b/cli/internal/terraform/terraform/openstack/modules/instance_group/main.tf index 2acfe7c13..a4a8f7e57 100644 --- a/cli/internal/terraform/terraform/openstack/modules/instance_group/main.tf +++ b/cli/internal/terraform/terraform/openstack/modules/instance_group/main.tf @@ -52,7 +52,9 @@ resource "openstack_compute_instance_v2" "instance_group_member" { constellation-uid = var.uid constellation-init-secret-hash = var.init_secret_hash openstack-auth-url = var.identity_internal_url + openstack-username = var.openstack_username + openstack-password = var.openstack_password + openstack-user-domain-name = var.openstack_user_domain_name } - user_data = var.openstack_service_account_token availability_zone_hints = var.availability_zone } diff --git a/cli/internal/terraform/terraform/openstack/modules/instance_group/variables.tf b/cli/internal/terraform/terraform/openstack/modules/instance_group/variables.tf index b974c7d75..6d21ef7dc 100644 --- a/cli/internal/terraform/terraform/openstack/modules/instance_group/variables.tf +++ b/cli/internal/terraform/terraform/openstack/modules/instance_group/variables.tf @@ -67,8 +67,17 @@ variable "identity_internal_url" { description = "Internal URL of the Identity service." } - -variable "openstack_service_account_token" { +variable "openstack_user_domain_name" { type = string - description = "OpenStack service account token." + description = "OpenStack user domain name." +} + +variable "openstack_username" { + type = string + description = "OpenStack user name." +} + +variable "openstack_password" { + type = string + description = "OpenStack password." } diff --git a/cli/internal/terraform/terraform/openstack/variables.tf b/cli/internal/terraform/terraform/openstack/variables.tf index 0fe6c60a8..086a58d1b 100644 --- a/cli/internal/terraform/terraform/openstack/variables.tf +++ b/cli/internal/terraform/terraform/openstack/variables.tf @@ -51,11 +51,20 @@ variable "floating_ip_pool_id" { description = "The pool (network name) to use for floating IPs." } -variable "openstack_service_account_token" { +variable "openstack_user_domain_name" { type = string - description = "OpenStack service account token." + description = "OpenStack user domain name." } +variable "openstack_username" { + type = string + description = "OpenStack user name." +} + +variable "openstack_password" { + type = string + description = "OpenStack password." +} variable "debug" { type = bool diff --git a/cli/internal/terraform/variables.go b/cli/internal/terraform/variables.go index ccfc82dbf..c56be7bba 100644 --- a/cli/internal/terraform/variables.go +++ b/cli/internal/terraform/variables.go @@ -233,8 +233,12 @@ type OpenStackClusterVariables struct { ImageURL string // DirectDownload decides whether to download the image directly from the URL to OpenStack or to upload it from the local machine. DirectDownload bool - // OpenStackServiceAccountToken is the OpenStack service account token to use. - OpenStackServiceAccountToken string + // OpenstackUserDomainName is the OpenStack user domain name to use. + OpenstackUserDomainName string + // OpenstackUsername is the OpenStack user name to use. + OpenstackUsername string + // OpenstackPassword is the OpenStack password to use. + OpenstackPassword string // Debug is true if debug mode is enabled. Debug bool } @@ -251,7 +255,9 @@ func (v *OpenStackClusterVariables) String() string { writeLinef(b, "floating_ip_pool_id = %q", v.FloatingIPPoolID) writeLinef(b, "image_url = %q", v.ImageURL) writeLinef(b, "direct_download = %t", v.DirectDownload) - writeLinef(b, "openstack_service_account_token = %q", v.OpenStackServiceAccountToken) + writeLinef(b, "openstack_user_domain_name = %q", v.OpenstackUserDomainName) + writeLinef(b, "openstack_username = %q", v.OpenstackUsername) + writeLinef(b, "openstack_password = %q", v.OpenstackPassword) writeLinef(b, "debug = %t", v.Debug) return b.String() diff --git a/internal/config/config.go b/internal/config/config.go index d77fdc1b2..3ecce11f3 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -238,8 +238,14 @@ type OpenStackConfig struct { // Floating IP pool to use for the VMs. For details see: https://docs.openstack.org/ocata/user-guide/cli-manage-ip-addresses.html FloatingIPPoolID string `yaml:"floatingIPPoolID" validate:"required"` // description: | - // Service account token to use authenticate VMs with the OpenStack API. Alternatively leave empty and pass value via CONSTELL_OPENSTACK_SERVICE_ACCOUNT_TOKEN environment variable. - ServiceAccountToken string `yaml:"serviceAccountToken" validate:"required"` + // UserDomainName is the name of the domain where a user resides. + UserDomainName string `yaml:"userDomainName" validate:"required"` + // description: | + // Username to use inside the cluster. + Username string `yaml:"username" validate:"required"` + // description: | + // Password to use inside the cluster. You can instead use the environment variable "CONSTELL_OS_PASSWORD". + Password string `yaml:"password"` // description: | // If enabled, downloads OS image directly from source URL to OpenStack. Otherwise, downloads image to local machine and uploads to OpenStack. DirectDownload *bool `yaml:"directDownload" validate:"required"` @@ -368,9 +374,9 @@ func New(fileHandler file.Handler, name string, force bool) (*Config, error) { c.Provider.Azure.ClientSecretValue = clientSecretValue } - serviceAccountToken := os.Getenv(constants.EnvVarOpenStackServiceAccountToken) - if serviceAccountToken != "" && c.Provider.OpenStack != nil { - c.Provider.OpenStack.ServiceAccountToken = serviceAccountToken + openstackPassword := os.Getenv(constants.EnvVarOpenStackPassword) + if openstackPassword != "" && c.Provider.OpenStack != nil { + c.Provider.OpenStack.Password = openstackPassword } // Backwards compatibility: configs without the field `microserviceVersion` are valid in version 2.6. diff --git a/internal/config/config_doc.go b/internal/config/config_doc.go index bae959b1e..852f5d098 100644 --- a/internal/config/config_doc.go +++ b/internal/config/config_doc.go @@ -330,7 +330,7 @@ func init() { FieldName: "openstack", }, } - OpenStackConfigDoc.Fields = make([]encoder.Doc, 6) + OpenStackConfigDoc.Fields = make([]encoder.Doc, 8) OpenStackConfigDoc.Fields[0].Name = "cloud" OpenStackConfigDoc.Fields[0].Type = "string" OpenStackConfigDoc.Fields[0].Note = "" @@ -351,16 +351,26 @@ func init() { OpenStackConfigDoc.Fields[3].Note = "" OpenStackConfigDoc.Fields[3].Description = "Floating IP pool to use for the VMs. For details see: https://docs.openstack.org/ocata/user-guide/cli-manage-ip-addresses.html" OpenStackConfigDoc.Fields[3].Comments[encoder.LineComment] = "Floating IP pool to use for the VMs. For details see: https://docs.openstack.org/ocata/user-guide/cli-manage-ip-addresses.html" - OpenStackConfigDoc.Fields[4].Name = "serviceAccountToken" + OpenStackConfigDoc.Fields[4].Name = "userDomainName" OpenStackConfigDoc.Fields[4].Type = "string" OpenStackConfigDoc.Fields[4].Note = "" - OpenStackConfigDoc.Fields[4].Description = "Service account token to use authenticate VMs with the OpenStack API. Alternatively leave empty and pass value via CONSTELL_OPENSTACK_SERVICE_ACCOUNT_TOKEN environment variable." - OpenStackConfigDoc.Fields[4].Comments[encoder.LineComment] = "Service account token to use authenticate VMs with the OpenStack API. Alternatively leave empty and pass value via CONSTELL_OPENSTACK_SERVICE_ACCOUNT_TOKEN environment variable." - OpenStackConfigDoc.Fields[5].Name = "directDownload" - OpenStackConfigDoc.Fields[5].Type = "bool" + OpenStackConfigDoc.Fields[4].Description = "UserDomainName is the name of the domain where a user resides." + OpenStackConfigDoc.Fields[4].Comments[encoder.LineComment] = "UserDomainName is the name of the domain where a user resides." + OpenStackConfigDoc.Fields[5].Name = "username" + OpenStackConfigDoc.Fields[5].Type = "string" OpenStackConfigDoc.Fields[5].Note = "" - OpenStackConfigDoc.Fields[5].Description = "If enabled, downloads OS image directly from source URL to OpenStack. Otherwise, downloads image to local machine and uploads to OpenStack." - OpenStackConfigDoc.Fields[5].Comments[encoder.LineComment] = "If enabled, downloads OS image directly from source URL to OpenStack. Otherwise, downloads image to local machine and uploads to OpenStack." + OpenStackConfigDoc.Fields[5].Description = "Username to use inside the cluster." + OpenStackConfigDoc.Fields[5].Comments[encoder.LineComment] = "Username to use inside the cluster." + OpenStackConfigDoc.Fields[6].Name = "password" + OpenStackConfigDoc.Fields[6].Type = "string" + OpenStackConfigDoc.Fields[6].Note = "" + OpenStackConfigDoc.Fields[6].Description = "Password to use inside the cluster. You can instead use the environment variable \"CONSTELL_OS_PASSWORD\"." + OpenStackConfigDoc.Fields[6].Comments[encoder.LineComment] = "Password to use inside the cluster. You can instead use the environment variable \"CONSTELL_OS_PASSWORD\"." + OpenStackConfigDoc.Fields[7].Name = "directDownload" + OpenStackConfigDoc.Fields[7].Type = "bool" + OpenStackConfigDoc.Fields[7].Note = "" + OpenStackConfigDoc.Fields[7].Description = "If enabled, downloads OS image directly from source URL to OpenStack. Otherwise, downloads image to local machine and uploads to OpenStack." + OpenStackConfigDoc.Fields[7].Comments[encoder.LineComment] = "If enabled, downloads OS image directly from source URL to OpenStack. Otherwise, downloads image to local machine and uploads to OpenStack." QEMUConfigDoc.Type = "QEMUConfig" QEMUConfigDoc.Comments[encoder.LineComment] = "QEMUConfig holds config information for QEMU based Constellation deployments." diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 3a2478878..f5c30ca99 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -184,7 +184,7 @@ func TestNewWithDefaultOptions(t *testing.T) { } func TestValidate(t *testing.T) { - const defaultErrCount = 25 // expect this number of error messages by default because user-specific values are not set and multiple providers are defined by default + const defaultErrCount = 26 // expect this number of error messages by default because user-specific values are not set and multiple providers are defined by default const azErrCount = 9 const gcpErrCount = 6 diff --git a/internal/constants/constants.go b/internal/constants/constants.go index eea2dee72..a24e8403b 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -145,9 +145,9 @@ const ( // EnvVarAzureClientSecretValue is environment variable to overwrite // provider.azure.clientSecretValue . EnvVarAzureClientSecretValue = EnvVarPrefix + "AZURE_CLIENT_SECRET_VALUE" - // EnvVarOpenStackServiceAccountToken is environment variable to overwrite - // provider.openstack.serviceAccountToken . - EnvVarOpenStackServiceAccountToken = EnvVarPrefix + "OPENSTACK_SERVICE_ACCOUNT_TOKEN" + // EnvVarOpenStackPassword is environment variable to overwrite + // provider.openstack.password . + EnvVarOpenStackPassword = EnvVarPrefix + "OS_PASSWORD" // EnvVarNoSpinner is environment variable used to disable the loading indicator (spinner) // displayed in Constellation CLI. Any non-empty value, e.g., CONSTELL_NO_SPINNER=1, // can be used to disable the spinner.