diff --git a/internal/services/machinelearning/machine_learning_compute_instance_resource.go b/internal/services/machinelearning/machine_learning_compute_instance_resource.go new file mode 100644 index 000000000000..76ba4465f01f --- /dev/null +++ b/internal/services/machinelearning/machine_learning_compute_instance_resource.go @@ -0,0 +1,327 @@ +package machinelearning + +import ( + "fmt" + "log" + "regexp" + "strings" + "time" + + "github.com/Azure/azure-sdk-for-go/services/machinelearningservices/mgmt/2021-07-01/machinelearningservices" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/location" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/machinelearning/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/machinelearning/validate" + networkValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tags" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func resourceComputeInstance() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceComputeInstanceCreate, + Read: resourceComputeInstanceRead, + Delete: resourceComputeInstanceDelete, + + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, err := parse.ComputeID(id) + return err + }), + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringMatch( + regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9-]{2,16}$`), + "It can include letters, digits and dashes. It must start with a letter, end with a letter or digit, and be between 2 and 16 characters in length."), + }, + + "machine_learning_workspace_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.WorkspaceID, + }, + + "location": azure.SchemaLocation(), + + "virtual_machine_size": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: suppress.CaseDifference, + }, + + "authorization_type": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(machinelearningservices.ComputeInstanceAuthorizationTypePersonal), + }, false), + }, + + "assign_to_user": {Type: pluginsdk.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "tenant_id": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "object_id": { + Type: pluginsdk.TypeString, + Optional: true, + }, + }, + }, + }, + + "description": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + }, + + "identity": SystemAssignedUserAssigned{}.Schema(), + + "ssh": { + Type: pluginsdk.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "public_key": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "username": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "port": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + }, + }, + }, + + "subnet_resource_id": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: networkValidate.SubnetID, + }, + + "tags": tags.ForceNewSchema(), + }, + } +} + +func resourceComputeInstanceCreate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).MachineLearning.MachineLearningComputeClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + workspaceID, _ := parse.WorkspaceID(d.Get("machine_learning_workspace_id").(string)) + id := parse.NewComputeID(subscriptionId, workspaceID.ResourceGroup, workspaceID.Name, d.Get("name").(string)) + + if d.IsNewResource() { + existing, err := client.Get(ctx, id.ResourceGroup, id.WorkspaceName, id.Name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for existing Machine Learning Compute (%q): %+v", id, err) + } + } + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_machine_learning_compute_instance", id.ID()) + } + } + + identity, err := SystemAssignedUserAssigned{}.Expand(d.Get("identity").([]interface{})) + if err != nil { + return err + } + + var subnet *machinelearningservices.ResourceID + if subnetId, ok := d.GetOk("subnet_resource_id"); ok { + subnet = &machinelearningservices.ResourceID{ + ID: utils.String(subnetId.(string)), + } + } + + parameters := machinelearningservices.ComputeResource{ + Properties: &machinelearningservices.ComputeInstance{ + Properties: &machinelearningservices.ComputeInstanceProperties{ + VMSize: utils.String(d.Get("virtual_machine_size").(string)), + Subnet: subnet, + SSHSettings: expandComputeSSHSetting(d.Get("ssh").([]interface{})), + ComputeInstanceAuthorizationType: machinelearningservices.ComputeInstanceAuthorizationType(d.Get("authorization_type").(string)), + PersonalComputeInstanceSettings: expandComputePersonalComputeInstanceSetting(d.Get("assign_to_user").([]interface{})), + }, + ComputeLocation: utils.String(d.Get("location").(string)), + Description: utils.String(d.Get("description").(string)), + }, + Identity: identity, + Location: utils.String(location.Normalize(d.Get("location").(string))), + Tags: tags.Expand(d.Get("tags").(map[string]interface{})), + } + + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.WorkspaceName, id.Name, parameters) + if err != nil { + return fmt.Errorf("creating Machine Learning Compute (%q): %+v", id, err) + } + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for creation of Machine Learning Compute (%q): %+v", id, err) + } + + d.SetId(id.ID()) + + return resourceComputeInstanceRead(d, meta) +} + +func resourceComputeInstanceRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).MachineLearning.MachineLearningComputeClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ComputeID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.WorkspaceName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] Machine Learning Compute %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("retrieving Machine Learning Compute (%q): %+v", id, err) + } + + d.Set("name", id.Name) + workspaceId := parse.NewWorkspaceID(subscriptionId, id.ResourceGroup, id.WorkspaceName) + d.Set("machine_learning_workspace_id", workspaceId.ID()) + + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + + identity, err := SystemAssignedUserAssigned{}.Flatten(resp.Identity) + if err != nil { + return err + } + d.Set("identity", identity) + + if props, ok := resp.Properties.AsComputeInstance(); ok && props != nil { + d.Set("description", props.Description) + if props.Properties != nil { + d.Set("virtual_machine_size", props.Properties.VMSize) + if props.Properties.Subnet != nil { + d.Set("subnet_resource_id", props.Properties.Subnet.ID) + } + d.Set("authorization_type", props.Properties.ComputeInstanceAuthorizationType) + d.Set("ssh", flattenComputeSSHSetting(props.Properties.SSHSettings)) + d.Set("assign_to_user", flattenComputePersonalComputeInstanceSetting(props.Properties.PersonalComputeInstanceSettings)) + } + } else { + return fmt.Errorf("compute resource %s is not a ComputeInstance Compute", id) + } + + return tags.FlattenAndSet(d, resp.Tags) +} + +func resourceComputeInstanceDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).MachineLearning.MachineLearningComputeClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + id, err := parse.ComputeID(d.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.WorkspaceName, id.Name, machinelearningservices.UnderlyingResourceActionDetach) + if err != nil { + return fmt.Errorf("deleting Machine Learning Compute (%q): %+v", id, err) + } + + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for deletion of the Machine Learning Compute (%q): %+v", id, err) + } + return nil +} + +func expandComputePersonalComputeInstanceSetting(input []interface{}) *machinelearningservices.PersonalComputeInstanceSettings { + if len(input) == 0 { + return nil + } + value := input[0].(map[string]interface{}) + return &machinelearningservices.PersonalComputeInstanceSettings{ + AssignedUser: &machinelearningservices.AssignedUser{ + ObjectID: utils.String(value["object_id"].(string)), + TenantID: utils.String(value["tenant_id"].(string)), + }} +} + +func expandComputeSSHSetting(input []interface{}) *machinelearningservices.ComputeInstanceSSHSettings { + if len(input) == 0 { + return &machinelearningservices.ComputeInstanceSSHSettings{ + SSHPublicAccess: machinelearningservices.SSHPublicAccessDisabled, + } + } + value := input[0].(map[string]interface{}) + return &machinelearningservices.ComputeInstanceSSHSettings{ + SSHPublicAccess: machinelearningservices.SSHPublicAccessEnabled, + AdminPublicKey: utils.String(value["public_key"].(string)), + } +} + +func flattenComputePersonalComputeInstanceSetting(settings *machinelearningservices.PersonalComputeInstanceSettings) interface{} { + if settings == nil || settings.AssignedUser == nil { + return []interface{}{} + } + return []interface{}{ + map[string]interface{}{ + "tenant_id": settings.AssignedUser.TenantID, + "object_id": settings.AssignedUser.ObjectID, + }, + } +} + +func flattenComputeSSHSetting(settings *machinelearningservices.ComputeInstanceSSHSettings) interface{} { + if settings == nil || strings.EqualFold(string(settings.SSHPublicAccess), string(machinelearningservices.SSHPublicAccessDisabled)) { + return []interface{}{} + } + + return []interface{}{ + map[string]interface{}{ + "public_key": settings.AdminPublicKey, + "username": settings.AdminUserName, + "port": settings.SSHPort, + }, + } +} diff --git a/internal/services/machinelearning/machine_learning_compute_instance_resource_test.go b/internal/services/machinelearning/machine_learning_compute_instance_resource_test.go new file mode 100644 index 000000000000..60d43c188270 --- /dev/null +++ b/internal/services/machinelearning/machine_learning_compute_instance_resource_test.go @@ -0,0 +1,341 @@ +package machinelearning_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/machinelearning/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type ComputeInstanceResource struct{} + +func TestAccComputeInstance_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_machine_learning_compute_instance", "test") + r := ComputeInstanceResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccComputeInstance_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_machine_learning_compute_instance", "test") + r := ComputeInstanceResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("ssh.0.username").Exists(), + check.That(data.ResourceName).Key("ssh.0.port").Exists(), + ), + }, + data.ImportStep(), + }) +} + +func TestAccComputeInstance_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_machine_learning_compute_instance", "test") + r := ComputeInstanceResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccComputeInstance_identity(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_machine_learning_compute_instance", "test") + r := ComputeInstanceResource{} + + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.identitySystemAssignedUserAssigned(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("identity.0.principal_id").MatchesRegex(validate.UUIDRegExp), + check.That(data.ResourceName).Key("identity.0.tenant_id").Exists(), + ), + }, + data.ImportStep(), + { + Config: r.identityUserAssigned(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.identitySystemAssigned(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("identity.0.principal_id").MatchesRegex(validate.UUIDRegExp), + check.That(data.ResourceName).Key("identity.0.tenant_id").Exists(), + ), + }, + data.ImportStep(), + }) +} + +func (r ComputeInstanceResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + computeClient := client.MachineLearning.MachineLearningComputeClient + id, err := parse.ComputeID(state.ID) + + if err != nil { + return nil, err + } + + computeResource, err := computeClient.Get(ctx, id.ResourceGroup, id.WorkspaceName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(computeResource.Response) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving Machine Learning Compute Cluster %q: %+v", state.ID, err) + } + return utils.Bool(computeResource.Properties != nil), nil +} + +func (r ComputeInstanceResource) basic(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_machine_learning_compute_instance" "test" { + name = "acctest%d" + location = azurerm_resource_group.test.location + machine_learning_workspace_id = azurerm_machine_learning_workspace.test.id + virtual_machine_size = "STANDARD_DS2_V2" +} +`, template, data.RandomIntOfLength(8)) +} + +func (r ComputeInstanceResource) complete(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +variable "ssh_key" { + default = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt terraform@demo.tld" +} + +resource "azurerm_virtual_network" "test" { + name = "acctest%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test" { + name = "internal" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] +} + +resource "azurerm_network_security_group" "test" { + name = "test-nsg-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + security_rule { + name = "test123" + priority = 100 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "29876-44224" + source_address_prefix = "*" + destination_address_prefix = "*" + } +} + +resource "azurerm_subnet_network_security_group_association" "test" { + subnet_id = azurerm_subnet.test.id + network_security_group_id = azurerm_network_security_group.test.id +} + +resource "azurerm_machine_learning_compute_instance" "test" { + name = "acctest%d" + location = azurerm_resource_group.test.location + machine_learning_workspace_id = azurerm_machine_learning_workspace.test.id + virtual_machine_size = "STANDARD_DS2_V2" + authorization_type = "personal" + ssh { + public_key = var.ssh_key + } + subnet_resource_id = azurerm_subnet.test.id + description = "this is desc" + tags = { + Label1 = "Value1" + } + depends_on = [ + azurerm_subnet_network_security_group_association.test + ] +} +`, template, data.RandomIntOfLength(8), data.RandomIntOfLength(8), data.RandomIntOfLength(8)) +} + +func (r ComputeInstanceResource) requiresImport(data acceptance.TestData) string { + template := r.basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_machine_learning_compute_instance" "import" { + name = azurerm_machine_learning_compute_instance.test.name + location = azurerm_machine_learning_compute_instance.test.location + machine_learning_workspace_id = azurerm_machine_learning_compute_instance.test.machine_learning_workspace_id + virtual_machine_size = "STANDARD_DS2_V2" +} +`, template) +} + +func (r ComputeInstanceResource) identitySystemAssigned(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_machine_learning_compute_instance" "test" { + name = "acctest%d" + location = azurerm_resource_group.test.location + machine_learning_workspace_id = azurerm_machine_learning_workspace.test.id + virtual_machine_size = "STANDARD_DS2_V2" + identity { + type = "SystemAssigned" + } +} +`, template, data.RandomIntOfLength(8)) +} + +func (r ComputeInstanceResource) identityUserAssigned(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_user_assigned_identity" "test" { + name = "acctestUAI-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_machine_learning_compute_instance" "test" { + name = "acctest%d" + location = azurerm_resource_group.test.location + machine_learning_workspace_id = azurerm_machine_learning_workspace.test.id + virtual_machine_size = "STANDARD_DS2_V2" + identity { + type = "UserAssigned" + identity_ids = [ + azurerm_user_assigned_identity.test.id, + ] + } +} +`, template, data.RandomInteger, data.RandomIntOfLength(8)) +} + +func (r ComputeInstanceResource) identitySystemAssignedUserAssigned(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_user_assigned_identity" "test" { + name = "acctestUAI-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_machine_learning_compute_instance" "test" { + name = "acctest%d" + location = azurerm_resource_group.test.location + machine_learning_workspace_id = azurerm_machine_learning_workspace.test.id + virtual_machine_size = "STANDARD_DS2_V2" + identity { + type = "SystemAssigned,UserAssigned" + identity_ids = [ + azurerm_user_assigned_identity.test.id, + ] + } +} +`, template, data.RandomInteger, data.RandomIntOfLength(8)) +} + +func (r ComputeInstanceResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_client_config" "current" {} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-ml-%[1]d" + location = "%[2]s" + tags = { + "stage" = "test" + } +} + +resource "azurerm_application_insights" "test" { + name = "acctestai-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + application_type = "web" +} + +resource "azurerm_key_vault" "test" { + name = "acctestvault%[3]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + tenant_id = data.azurerm_client_config.current.tenant_id + sku_name = "standard" + purge_protection_enabled = true +} + +resource "azurerm_storage_account" "test" { + name = "acctestsa%[4]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_machine_learning_workspace" "test" { + name = "acctest-MLW%[5]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + application_insights_id = azurerm_application_insights.test.id + key_vault_id = azurerm_key_vault.test.id + storage_account_id = azurerm_storage_account.test.id + identity { + type = "SystemAssigned" + } +} +`, data.RandomInteger, data.Locations.Primary, + data.RandomIntOfLength(12), data.RandomIntOfLength(15), data.RandomIntOfLength(16), + data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} diff --git a/internal/services/machinelearning/registration.go b/internal/services/machinelearning/registration.go index 58a53776aaa0..cd5aa51a8bed 100644 --- a/internal/services/machinelearning/registration.go +++ b/internal/services/machinelearning/registration.go @@ -30,6 +30,7 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { "azurerm_machine_learning_workspace": resourceMachineLearningWorkspace(), "azurerm_machine_learning_inference_cluster": resourceAksInferenceCluster(), "azurerm_machine_learning_compute_cluster": resourceComputeCluster(), + "azurerm_machine_learning_compute_instance": resourceComputeInstance(), "azurerm_machine_learning_synapse_spark": resourceSynapseSpark(), } } diff --git a/website/docs/r/machine_learning_compute_instance.html.markdown b/website/docs/r/machine_learning_compute_instance.html.markdown new file mode 100644 index 000000000000..5af8ef150522 --- /dev/null +++ b/website/docs/r/machine_learning_compute_instance.html.markdown @@ -0,0 +1,185 @@ +--- +subcategory: "Machine Learning" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_machine_learning_compute_instance" +description: |- + Manages a Machine Learning Compute Instance. +--- + +# azurerm_machine_learning_compute_instance + +Manages a Machine Learning Compute Instance. + +## Example Usage + +```hcl +data "azurerm_client_config" "current" {} +resource "azurerm_resource_group" "example" { + name = "example-rg" + location = "west europe" + tags = { + "stage" = "example" + } +} + +resource "azurerm_application_insights" "example" { + name = "example-ai" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + application_type = "web" +} + +resource "azurerm_key_vault" "example" { + name = "example-kv" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + tenant_id = data.azurerm_client_config.current.tenant_id + sku_name = "standard" + purge_protection_enabled = true +} + +resource "azurerm_storage_account" "example" { + name = "examplesa" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_machine_learning_workspace" "example" { + name = "example-mlw" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + application_insights_id = azurerm_application_insights.example.id + key_vault_id = azurerm_key_vault.example.id + storage_account_id = azurerm_storage_account.example.id + identity { + type = "SystemAssigned" + } +} + +resource "azurerm_virtual_network" "example" { + name = "example-vnet" + address_space = ["10.1.0.0/16"] + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name +} + +resource "azurerm_subnet" "example" { + name = "example-subnet" + resource_group_name = azurerm_resource_group.example.name + virtual_network_name = azurerm_virtual_network.example.name + address_prefixes = ["10.1.0.0/24"] +} + +variable "ssh_key" { + default = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt terraform@demo.tld" +} + +resource "azurerm_machine_learning_compute_instance" "example" { + name = "example" + location = azurerm_resource_group.example.location + machine_learning_workspace_id = azurerm_machine_learning_workspace.example.id + virtual_machine_size = "STANDARD_DS2_V2" + authorization_type = "personal" + ssh { + public_key = var.ssh_key + } + subnet_resource_id = azurerm_subnet.example.id + description = "foo" + tags = { + foo = "bar" + } +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) The name which should be used for this Machine Learning Compute Instance. Changing this forces a new Machine Learning Compute Instance to be created. + +* `location` - (Required) The Azure Region where the Machine Learning Compute Instance should exist. Changing this forces a new Machine Learning Compute Instance to be created. + +* `machine_learning_workspace_id` - (Required) The ID of the Machine Learning Workspace. Changing this forces a new Machine Learning Compute Instance to be created. + +* `virtual_machine_size` - (Required) The Virtual Machine Size. Changing this forces a new Machine Learning Compute Instance to be created. + +--- + +* `authorization_type` - (Optional) The Compute Instance Authorization type. Possible values include: `personal`. Changing this forces a new Machine Learning Compute Instance to be created. + +* `assign_to_user` - (Optional) A `assign_to_user` block as defined below. A user explicitly assigned to a personal compute instance. Changing this forces a new Machine Learning Compute Instance to be created. + +* `description` - (Optional) The description of the Machine Learning Compute Instance. Changing this forces a new Machine Learning Compute Instance to be created. + +* `identity` - (Optional) A `identity` block as defined below. Changing this forces a new Machine Learning Compute Instance to be created. + +* `ssh` - (Optional) A `ssh` block as defined below. Specifies policy and settings for SSH access. Changing this forces a new Machine Learning Compute Instance to be created. + +* `subnet_resource_id` - (Optional) Virtual network subnet resource ID the compute nodes belong to. Changing this forces a new Machine Learning Compute Instance to be created. + +* `tags` - (Optional) A mapping of tags which should be assigned to the Machine Learning Compute Instance. Changing this forces a new Machine Learning Compute Instance to be created. + +--- + +A `identity` block supports the following: + +* `type` - (Required) The Type of Identity which should be used for this Machine Learning Compute Instance. Possible values are `SystemAssigned`, `UserAssigned` and `SystemAssigned,UserAssigned`. Changing this forces a new Machine Learning Compute Instance to be created. + +* `identity_ids` - (Optional) A list of User Managed Identity ID's which should be assigned to the Machine Learning Compute Instance. Changing this forces a new Machine Learning Compute Instance to be created. + +--- + +A `assign_to_user` block supports the following: + +* `object_id` - (Optional) User’s AAD Object Id. + +* `tenant_id` - (Optional) User’s AAD Tenant Id. + +--- + +A `ssh` block supports the following: + +* `public_key` - (Required) Specifies the SSH rsa public key file as a string. Use "ssh-keygen -t rsa -b 2048" to generate your SSH key pairs. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Machine Learning Compute Instance. + +* `identity` - An `identity` block as defined below, which contains the Managed Service Identity information for this Machine Learning Compute Instance. + +* `ssh` - An `ssh` block as defined below, which specifies policy and settings for SSH access for this Machine Learning Compute Instance. + +--- + +A `identity` block exports the following: + +* `principal_id` - The Principal ID for the Service Principal associated with the Managed Service Identity of this Machine Learning Compute Instance. + +* `tenant_id` - The Tenant ID for the Service Principal associated with the Managed Service Identity of this Machine Learning Compute Instance. + +--- +A `ssh` block exports the following: + +* `username` - The admin username of this Machine Learning Compute Instance. + +* `port` - Describes the port for connecting through SSH. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Machine Learning Compute Instance. +* `read` - (Defaults to 5 minutes) Used when retrieving the Machine Learning Compute Instance. +* `delete` - (Defaults to 30 minutes) Used when deleting the Machine Learning Compute Instance. + +## Import + +Machine Learning Compute Instances can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_machine_learning_compute_instance.example C:/Program Files/Git/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.MachineLearningServices/workspaces/workspace1/computes/compute1 +```