diff --git a/azurerm/config.go b/azurerm/config.go index 15d761fb2e26..95e958c705b5 100644 --- a/azurerm/config.go +++ b/azurerm/config.go @@ -31,6 +31,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-04-01/network" "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2017-12-01/postgresql" "github.com/Azure/azure-sdk-for-go/services/preview/authorization/mgmt/2018-01-01-preview/authorization" + "github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi" "github.com/Azure/azure-sdk-for-go/services/preview/operationalinsights/mgmt/2015-11-01-preview/operationalinsights" "github.com/Azure/azure-sdk-for-go/services/preview/operationsmanagement/mgmt/2015-11-01-preview/operationsmanagement" "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/2015-05-01-preview/sql" @@ -149,6 +150,9 @@ type ArmClient struct { // Monitor monitorAlertRulesClient insights.AlertRulesClient + // MSI + userAssignedIdentitiesClient msi.UserAssignedIdentitiesClient + // Networking applicationGatewayClient network.ApplicationGatewaysClient applicationSecurityGroupsClient network.ApplicationSecurityGroupsClient @@ -793,6 +797,10 @@ func (c *ArmClient) registerNetworkingClients(endpoint, subscriptionId string, a c.configureClient(&subnetsClient.Client, auth) c.subnetClient = subnetsClient + userAssignedIdentitiesClient := msi.NewUserAssignedIdentitiesClientWithBaseURI(endpoint, subscriptionId) + c.configureClient(&userAssignedIdentitiesClient.Client, auth) + c.userAssignedIdentitiesClient = userAssignedIdentitiesClient + watchersClient := network.NewWatchersClientWithBaseURI(endpoint, subscriptionId) c.configureClient(&watchersClient.Client, auth) c.watcherClient = watchersClient diff --git a/azurerm/import_arm_user_assigned_identity_test.go b/azurerm/import_arm_user_assigned_identity_test.go new file mode 100644 index 000000000000..325ca34d86ab --- /dev/null +++ b/azurerm/import_arm_user_assigned_identity_test.go @@ -0,0 +1,35 @@ +package azurerm + +import ( + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccAzureRMUserAssignedIdentity_importBasic(t *testing.T) { + resourceName := "azurerm_user_assigned_identity.test" + + ri := acctest.RandInt() + location := testLocation() + rs := acctest.RandString(14) + config := testAccAzureRMUserAssignedIdentity_basic(ri, location, rs) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMUserAssignedIdentityDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +// diff --git a/azurerm/provider.go b/azurerm/provider.go index b38ad73285dc..a2a9bfe32577 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -224,6 +224,7 @@ func Provider() terraform.ResourceProvider { "azurerm_template_deployment": resourceArmTemplateDeployment(), "azurerm_traffic_manager_endpoint": resourceArmTrafficManagerEndpoint(), "azurerm_traffic_manager_profile": resourceArmTrafficManagerProfile(), + "azurerm_user_assigned_identity": resourceArmUserAssignedIdentity(), "azurerm_virtual_machine": resourceArmVirtualMachine(), "azurerm_virtual_machine_data_disk_attachment": resourceArmVirtualMachineDataDiskAttachment(), "azurerm_virtual_machine_extension": resourceArmVirtualMachineExtensions(), @@ -348,6 +349,7 @@ func determineAzureResourceProvidersToRegister(providerList []resources.Provider "Microsoft.EventHub": {}, "Microsoft.KeyVault": {}, "microsoft.insights": {}, + "Microsoft.ManagedIdentity": {}, "Microsoft.Network": {}, "Microsoft.OperationalInsights": {}, "Microsoft.Relay": {}, diff --git a/azurerm/resource_arm_user_assigned_identity.go b/azurerm/resource_arm_user_assigned_identity.go new file mode 100644 index 000000000000..768086bbb72f --- /dev/null +++ b/azurerm/resource_arm_user_assigned_identity.go @@ -0,0 +1,133 @@ +package azurerm + +import ( + "fmt" + "log" + + "github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmUserAssignedIdentity() *schema.Resource { + return &schema.Resource{ + Create: resourceArmUserAssignedIdentityCreateUpdate, + Read: resourceArmUserAssignedIdentityRead, + Update: resourceArmUserAssignedIdentityCreateUpdate, + Delete: resourceArmUserAssignedIdentityDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 24), + }, + + "resource_group_name": resourceGroupNameSchema(), + + "location": locationSchema(), + + "tags": tagsSchema(), + + "principal_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceArmUserAssignedIdentityCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).userAssignedIdentitiesClient + ctx := meta.(*ArmClient).StopContext + + log.Printf("[INFO] preparing arguments for Azure ARM user identity creation.") + + name := d.Get("name").(string) + location := d.Get("location").(string) + resGroup := d.Get("resource_group_name").(string) + tags := d.Get("tags").(map[string]interface{}) + identity := msi.Identity{ + Name: &name, + Location: &location, + Tags: expandTags(tags), + } + + _, err := client.CreateOrUpdate(ctx, resGroup, name, identity) + if err != nil { + return fmt.Errorf("Error Creating/Updating User Assigned Identity %q (Resource Group %q): %+v", name, resGroup, err) + } + + read, err := client.Get(ctx, resGroup, name) + if err != nil { + return err + } + + if read.ID == nil { + return fmt.Errorf("Cannot read User Assigned Identity %q ID (resource group %q) ID", name, resGroup) + } + + d.SetId(*read.ID) + + return resourceArmUserAssignedIdentityRead(d, meta) +} + +func resourceArmUserAssignedIdentityRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).userAssignedIdentitiesClient + ctx := meta.(*ArmClient).StopContext + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + + resGroup := id.ResourceGroup + name := id.Path["userAssignedIdentities"] + resp, err := client.Get(ctx, resGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("Error making Read request on User Assigned Identity %q (Resource Group %q): %+v", name, resGroup, err) + } + + d.Set("name", resp.Name) + d.Set("resource_group_name", resGroup) + d.Set("location", resp.Location) + + if props := resp.IdentityProperties; props != nil { + if principalId := props.PrincipalID; principalId != nil { + d.Set("principal_id", principalId.String()) + } + } + + flattenAndSetTags(d, resp.Tags) + + return nil +} + +func resourceArmUserAssignedIdentityDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).userAssignedIdentitiesClient + ctx := meta.(*ArmClient).StopContext + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + + resGroup := id.ResourceGroup + name := id.Path["userAssignedIdentities"] + + _, err = client.Delete(ctx, resGroup, name) + if err != nil { + return fmt.Errorf("Error deleting User Assigned Identity %q (Resource Group %q): %+v", name, resGroup, err) + } + + return nil +} diff --git a/azurerm/resource_arm_user_assigned_identity_test.go b/azurerm/resource_arm_user_assigned_identity_test.go new file mode 100644 index 000000000000..6dc61cc0525d --- /dev/null +++ b/azurerm/resource_arm_user_assigned_identity_test.go @@ -0,0 +1,108 @@ +package azurerm + +import ( + "fmt" + "regexp" + "testing" + + "net/http" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAzureRMUserAssignedIdentity_basic(t *testing.T) { + principalIdRegex := "^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$" + resourceName := "azurerm_user_assigned_identity.test" + ri := acctest.RandInt() + rs := acctest.RandString(14) + config := testAccAzureRMUserAssignedIdentity_basic(ri, testLocation(), rs) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMUserAssignedIdentityDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMUserAssignedIdentityExists(resourceName), + resource.TestMatchResourceAttr(resourceName, "principal_id", regexp.MustCompile(principalIdRegex)), + ), + }, + }, + }) +} + +func testCheckAzureRMUserAssignedIdentityExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + name := rs.Primary.Attributes["name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for virtual machine: %s", name) + } + + client := testAccProvider.Meta().(*ArmClient).userAssignedIdentitiesClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + return fmt.Errorf("Bad: Get on userAssignedIdentitiesClient: %+v", err) + } + + if resp.StatusCode == http.StatusNotFound { + return fmt.Errorf("Bad: User Assigned Identity %q (resource group: %q) does not exist", name, resourceGroup) + } + + return nil + } +} + +func testCheckAzureRMUserAssignedIdentityDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*ArmClient).userAssignedIdentitiesClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_virtual_machine" { + continue + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + resp, err := client.Get(ctx, resourceGroup, name) + + if err != nil { + if resp.StatusCode == http.StatusNotFound { + return nil + } + + return err + } + + return fmt.Errorf("User Assigned Identity still exists:\n%#v", resp) + } + + return nil +} + +func testAccAzureRMUserAssignedIdentity_basic(rInt int, location string, rString string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_user_assigned_identity" "test" { + name = "acctest%s" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" +} +`, rInt, location, rString) +} diff --git a/azurerm/resource_arm_virtual_machine.go b/azurerm/resource_arm_virtual_machine.go index aa2320d7c424..4a4dde26b0c0 100644 --- a/azurerm/resource_arm_virtual_machine.go +++ b/azurerm/resource_arm_virtual_machine.go @@ -86,13 +86,21 @@ func resourceArmVirtualMachine() *schema.Resource { Required: true, DiffSuppressFunc: ignoreCaseDiffSuppressFunc, ValidateFunc: validation.StringInSlice([]string{ - "SystemAssigned", - }, true), + string(compute.ResourceIdentityTypeSystemAssigned), + string(compute.ResourceIdentityTypeUserAssigned), + }, false), }, "principal_id": { Type: schema.TypeString, Computed: true, }, + "identity_ids": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, }, }, }, @@ -955,6 +963,14 @@ func flattenAzureRmVirtualMachineIdentity(identity *compute.VirtualMachineIdenti result["principal_id"] = *identity.PrincipalID } + identity_ids := make([]string, 0) + if identity.IdentityIds != nil { + for _, id := range *identity.IdentityIds { + identity_ids = append(identity_ids, id) + } + } + result["identity_ids"] = identity_ids + return []interface{}{result} } @@ -1181,10 +1197,22 @@ func expandAzureRmVirtualMachineIdentity(d *schema.ResourceData) *compute.Virtua v := d.Get("identity") identities := v.([]interface{}) identity := identities[0].(map[string]interface{}) - identityType := identity["type"].(string) - return &compute.VirtualMachineIdentity{ - Type: compute.ResourceIdentityType(identityType), + identityType := compute.ResourceIdentityType(identity["type"].(string)) + + identityIds := []string{} + for _, id := range identity["identity_ids"].([]interface{}) { + identityIds = append(identityIds, id.(string)) + } + + vmIdentity := compute.VirtualMachineIdentity{ + Type: identityType, } + + if vmIdentity.Type == compute.ResourceIdentityTypeUserAssigned { + vmIdentity.IdentityIds = &identityIds + } + + return &vmIdentity } func expandAzureRmVirtualMachineOsProfile(d *schema.ResourceData) (*compute.OSProfile, error) { diff --git a/azurerm/resource_arm_virtual_machine_scale_set.go b/azurerm/resource_arm_virtual_machine_scale_set.go index d095b7357423..d277736520af 100644 --- a/azurerm/resource_arm_virtual_machine_scale_set.go +++ b/azurerm/resource_arm_virtual_machine_scale_set.go @@ -49,8 +49,16 @@ func resourceArmVirtualMachineScaleSet() *schema.Resource { Required: true, DiffSuppressFunc: ignoreCaseDiffSuppressFunc, ValidateFunc: validation.StringInSlice([]string{ - "SystemAssigned", - }, true), + string(compute.ResourceIdentityTypeSystemAssigned), + string(compute.ResourceIdentityTypeUserAssigned), + }, false), + }, + "identity_ids": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, }, "principal_id": { Type: schema.TypeString, @@ -932,6 +940,14 @@ func flattenAzureRmVirtualMachineScaleSetIdentity(identity *compute.VirtualMachi result["principal_id"] = *identity.PrincipalID } + identity_ids := make([]string, 0) + if identity.IdentityIds != nil { + for _, id := range *identity.IdentityIds { + identity_ids = append(identity_ids, id) + } + } + result["identity_ids"] = identity_ids + return []interface{}{result} } @@ -1635,10 +1651,22 @@ func expandAzureRmVirtualMachineScaleSetIdentity(d *schema.ResourceData) *comput v := d.Get("identity") identities := v.([]interface{}) identity := identities[0].(map[string]interface{}) - identityType := identity["type"].(string) - return &compute.VirtualMachineScaleSetIdentity{ - Type: compute.ResourceIdentityType(identityType), + identityType := compute.ResourceIdentityType(identity["type"].(string)) + + identityIds := []string{} + for _, id := range identity["identity_ids"].([]interface{}) { + identityIds = append(identityIds, id.(string)) + } + + vmssIdentity := compute.VirtualMachineScaleSetIdentity{ + Type: identityType, } + + if vmssIdentity.Type == compute.ResourceIdentityTypeUserAssigned { + vmssIdentity.IdentityIds = &identityIds + } + + return &vmssIdentity } func expandAzureRMVirtualMachineScaleSetsStorageProfileOsDisk(d *schema.ResourceData) (*compute.VirtualMachineScaleSetOSDisk, error) { diff --git a/azurerm/resource_arm_virtual_machine_scale_set_test.go b/azurerm/resource_arm_virtual_machine_scale_set_test.go index 5ccd6dcdf638..2ea5bb886c09 100644 --- a/azurerm/resource_arm_virtual_machine_scale_set_test.go +++ b/azurerm/resource_arm_virtual_machine_scale_set_test.go @@ -517,10 +517,10 @@ func TestAccAzureRMVirtualMachineScaleSet_priority(t *testing.T) { }) } -func TestAccAzureRMVirtualMachineScaleSet_MSI(t *testing.T) { +func TestAccAzureRMVirtualMachineScaleSet_SystemAssignedMSI(t *testing.T) { resourceName := "azurerm_virtual_machine_scale_set.test" ri := acctest.RandInt() - config := testAccAzureRMVirtualMachineScaleSetMSITemplate(ri, testLocation()) + config := testAccAzureRMVirtualMachineScaleSetSystemAssignedMSI(ri, testLocation()) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -528,7 +528,35 @@ func TestAccAzureRMVirtualMachineScaleSet_MSI(t *testing.T) { Steps: []resource.TestStep{ { Config: config, - Check: resource.TestCheckResourceAttrSet(resourceName, "identity.0.principal_id"), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualMachineScaleSetExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "identity.0.type", "SystemAssigned"), + resource.TestCheckResourceAttr(resourceName, "identity.0.identity_ids.#", "0"), + resource.TestMatchResourceAttr(resourceName, "identity.0.principal_id", regexp.MustCompile(".+")), + ), + }, + }, + }) +} + +func TestAccAzureRMVirtualMachineScaleSet_UserAssignedMSI(t *testing.T) { + resourceName := "azurerm_virtual_machine_scale_set.test" + ri := acctest.RandInt() + rs := acctest.RandString(14) + config := testAccAzureRMVirtualMachineScaleSetUserAssignedMSI(ri, testLocation(), rs) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMVirtualMachineScaleSetDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualMachineScaleSetExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "identity.0.type", "UserAssigned"), + resource.TestCheckResourceAttr(resourceName, "identity.0.identity_ids.#", "1"), + resource.TestCheckResourceAttr(resourceName, "identity.0.principal_id", ""), + ), }, }, }) @@ -911,27 +939,6 @@ func testCheckAzureRMVirtualMachineScaleSetSinglePlacementGroup(name string, exp } } -func testCheckAzureRMVirtualMachineScaleSetMSI(name string) resource.TestCheckFunc { - return func(s *terraform.State) error { - resp, err := testGetAzureRMVirtualMachineScaleSet(s, name) - if err != nil { - return err - } - - identityType := resp.Identity.Type - if identityType != "systemAssigned" { - return fmt.Errorf("Bad: Identity Type is not systemAssigned for scale set %v", name) - } - - principalID := *resp.Identity.PrincipalID - if len(principalID) == 0 { - return fmt.Errorf("Bad: Could not get principal_id for scale set %v", name) - } - - return nil - } -} - func testCheckAzureRMVirtualMachineScaleSetExtension(name string) resource.TestCheckFunc { return func(s *terraform.State) error { resp, err := testGetAzureRMVirtualMachineScaleSet(s, name) @@ -2876,7 +2883,7 @@ resource "azurerm_virtual_machine_scale_set" "test" { `, rInt, location) } -func testAccAzureRMVirtualMachineScaleSetMSITemplate(rInt int, location string) string { +func testAccAzureRMVirtualMachineScaleSetSystemAssignedMSI(rInt int, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { name = "acctestRG-%[1]d" @@ -2926,7 +2933,7 @@ resource "azurerm_virtual_machine_scale_set" "test" { } identity { - type = "systemAssigned" + type = "SystemAssigned" } extension { @@ -2971,6 +2978,109 @@ resource "azurerm_virtual_machine_scale_set" "test" { `, rInt, location) } +func testAccAzureRMVirtualMachineScaleSetUserAssignedMSI(rInt int, location string, rString string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestrg-%[1]d" + location = "%[2]s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctvn-%[1]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 = "acctsub-%[1]d" + resource_group_name = "${azurerm_resource_group.test.name}" + virtual_network_name = "${azurerm_virtual_network.test.name}" + address_prefix = "10.0.2.0/24" +} + +resource "azurerm_storage_account" "test" { + name = "accsa%[1]d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_storage_container" "test" { + name = "vhds" + resource_group_name = "${azurerm_resource_group.test.name}" + storage_account_name = "${azurerm_storage_account.test.name}" + container_access_type = "private" +} + +resource "azurerm_user_assigned_identity" "test" { + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + + name = "acctest%[3]s" +} + +resource "azurerm_virtual_machine_scale_set" "test" { + name = "acctvmss-%[1]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + upgrade_policy_mode = "Manual" + overprovision = false + + sku { + name = "Standard_D1_v2" + tier = "Standard" + capacity = 1 + } + + identity { + type = "UserAssigned" + identity_ids = ["${azurerm_user_assigned_identity.test.id}"] + } + + extension { + name = "MSILinuxExtension" + publisher = "Microsoft.ManagedIdentity" + type = "ManagedIdentityExtensionForLinux" + type_handler_version = "1.0" + settings = "{\"port\": 50342}" + } + + os_profile { + computer_name_prefix = "testvm-%[1]d" + admin_username = "myadmin" + admin_password = "Passwword1234" + } + + network_profile { + name = "TestNetworkProfile" + primary = true + + ip_configuration { + name = "TestIPConfiguration" + subnet_id = "${azurerm_subnet.test.id}" + } + } + + storage_profile_os_disk { + name = "os-disk" + caching = "ReadWrite" + create_option = "FromImage" + vhd_containers = ["${azurerm_storage_account.test.primary_blob_endpoint}${azurerm_storage_container.test.name}"] + } + + storage_profile_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "16.04-LTS" + version = "latest" + } +} + +`, rInt, location, rString) +} + func testAccAzureRMVirtualMachineScaleSetExtensionTemplate(rInt int, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { diff --git a/azurerm/resource_arm_virtual_machine_test.go b/azurerm/resource_arm_virtual_machine_test.go index 722e8be9dee2..f9f4ddae570f 100644 --- a/azurerm/resource_arm_virtual_machine_test.go +++ b/azurerm/resource_arm_virtual_machine_test.go @@ -3,6 +3,7 @@ package azurerm import ( "fmt" "net/http" + "regexp" "testing" "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2017-12-01/compute" @@ -11,6 +12,74 @@ import ( "github.com/hashicorp/terraform/terraform" ) +func TestAccAzureRMVirtualMachine_winTimeZone(t *testing.T) { + resourceName := "azurerm_virtual_machine.test" + var vm compute.VirtualMachine + ri := acctest.RandInt() + config := testAccAzureRMVirtualMachine_winTimeZone(ri, testLocation()) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMVirtualMachineDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualMachineExists("azurerm_virtual_machine.test", &vm), + resource.TestCheckResourceAttr(resourceName, "os_profile_windows_config.59207889.timezone", "Pacific Standard Time"), + ), + }, + }, + }) +} + +func TestAccAzureRMVirtualMachine_SystemAssignedIdentity(t *testing.T) { + var vm compute.VirtualMachine + resourceName := "azurerm_virtual_machine.test" + ri := acctest.RandInt() + config := testAccAzureRMVirtualMachineSystemAssignedIdentity(ri, testLocation()) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMVirtualMachineScaleSetDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualMachineExists(resourceName, &vm), + resource.TestCheckResourceAttr(resourceName, "identity.0.type", "SystemAssigned"), + resource.TestCheckResourceAttr(resourceName, "identity.0.identity_ids.#", "0"), + resource.TestMatchResourceAttr(resourceName, "identity.0.principal_id", regexp.MustCompile(".+")), + ), + }, + }, + }) +} + +func TestAccAzureRMVirtualMachine_UserAssignedIdentity(t *testing.T) { + var vm compute.VirtualMachine + resourceName := "azurerm_virtual_machine.test" + ri := acctest.RandInt() + rs := acctest.RandString(14) + config := testAccAzureRMVirtualMachineUserAssignedIdentity(ri, testLocation(), rs) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMVirtualMachineScaleSetDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualMachineExists(resourceName, &vm), + resource.TestCheckResourceAttr(resourceName, "identity.0.type", "UserAssigned"), + resource.TestCheckResourceAttr(resourceName, "identity.0.identity_ids.#", "1"), + resource.TestCheckResourceAttr(resourceName, "identity.0.principal_id", ""), + ), + }, + }, + }) +} + func testCheckAzureRMVirtualMachineExists(name string, vm *compute.VirtualMachine) resource.TestCheckFunc { return func(s *terraform.State) error { // Ensure we have enough information in state to look up in API @@ -71,27 +140,6 @@ func testCheckAzureRMVirtualMachineDestroy(s *terraform.State) error { return nil } -func TestAccAzureRMVirtualMachine_winTimeZone(t *testing.T) { - resourceName := "azurerm_virtual_machine.test" - var vm compute.VirtualMachine - ri := acctest.RandInt() - config := testAccAzureRMVirtualMachine_winTimeZone(ri, testLocation()) - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testCheckAzureRMVirtualMachineDestroy, - Steps: []resource.TestStep{ - { - Config: config, - Check: resource.ComposeTestCheckFunc( - testCheckAzureRMVirtualMachineExists("azurerm_virtual_machine.test", &vm), - resource.TestCheckResourceAttr(resourceName, "os_profile_windows_config.59207889.timezone", "Pacific Standard Time"), - ), - }, - }, - }) -} - func testAccAzureRMVirtualMachine_winTimeZone(rInt int, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { @@ -173,3 +221,203 @@ resource "azurerm_virtual_machine" "test" { } `, rInt, location, rInt, rInt, rInt, rInt, rInt) } + +func testAccAzureRMVirtualMachineSystemAssignedIdentity(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctvn-%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 = "acctsub-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + virtual_network_name = "${azurerm_virtual_network.test.name}" + address_prefix = "10.0.2.0/24" +} + +resource "azurerm_network_interface" "test" { + name = "acctni-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + ip_configuration { + name = "testconfiguration1" + subnet_id = "${azurerm_subnet.test.id}" + private_ip_address_allocation = "dynamic" + } +} + +resource "azurerm_storage_account" "test" { + name = "accsa%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + account_tier = "Standard" + account_replication_type = "LRS" + + tags { + environment = "staging" + } +} + +resource "azurerm_storage_container" "test" { + name = "vhds" + resource_group_name = "${azurerm_resource_group.test.name}" + storage_account_name = "${azurerm_storage_account.test.name}" + container_access_type = "private" +} + +resource "azurerm_virtual_machine" "test" { + name = "acctvm-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + network_interface_ids = ["${azurerm_network_interface.test.id}"] + vm_size = "Standard_D1_v2" + + storage_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "16.04-LTS" + version = "latest" + } + + storage_os_disk { + name = "myosdisk1" + vhd_uri = "${azurerm_storage_account.test.primary_blob_endpoint}${azurerm_storage_container.test.name}/myosdisk1.vhd" + caching = "ReadWrite" + create_option = "FromImage" + disk_size_gb = "45" + } + + os_profile { + computer_name = "hn%d" + admin_username = "testadmin" + admin_password = "Password1234!" + } + + os_profile_linux_config { + disable_password_authentication = false + } + + tags { + environment = "Production" + cost-center = "Ops" + } + + identity { + type = "SystemAssigned" + } +} +`, rInt, location, rInt, rInt, rInt, rInt, rInt, rInt) +} + +func testAccAzureRMVirtualMachineUserAssignedIdentity(rInt int, location string, rString string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctvn-%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 = "acctsub-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + virtual_network_name = "${azurerm_virtual_network.test.name}" + address_prefix = "10.0.2.0/24" +} + +resource "azurerm_network_interface" "test" { + name = "acctni-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + ip_configuration { + name = "testconfiguration1" + subnet_id = "${azurerm_subnet.test.id}" + private_ip_address_allocation = "dynamic" + } +} + +resource "azurerm_storage_account" "test" { + name = "accsa%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + account_tier = "Standard" + account_replication_type = "LRS" + + tags { + environment = "staging" + } +} + +resource "azurerm_storage_container" "test" { + name = "vhds" + resource_group_name = "${azurerm_resource_group.test.name}" + storage_account_name = "${azurerm_storage_account.test.name}" + container_access_type = "private" +} + +resource "azurerm_user_assigned_identity" "test" { + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + + name = "acctest%s" +} + +resource "azurerm_virtual_machine" "test" { + name = "acctvm-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + network_interface_ids = ["${azurerm_network_interface.test.id}"] + vm_size = "Standard_D1_v2" + + storage_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "16.04-LTS" + version = "latest" + } + + storage_os_disk { + name = "myosdisk1" + vhd_uri = "${azurerm_storage_account.test.primary_blob_endpoint}${azurerm_storage_container.test.name}/myosdisk1.vhd" + caching = "ReadWrite" + create_option = "FromImage" + disk_size_gb = "45" + } + + os_profile { + computer_name = "hn%d" + admin_username = "testadmin" + admin_password = "Password1234!" + } + + os_profile_linux_config { + disable_password_authentication = false + } + + tags { + environment = "Production" + cost-center = "Ops" + } + + identity { + type = "UserAssigned" + identity_ids = ["${azurerm_user_assigned_identity.test.id}"] + } +} +`, rInt, location, rInt, rInt, rInt, rInt, rString, rInt, rInt) +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi/client.go b/vendor/github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi/client.go new file mode 100644 index 000000000000..a4e7c71d55b9 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi/client.go @@ -0,0 +1,51 @@ +// Package msi implements the Azure ARM Msi service API version 2015-08-31-preview. +// +// The Managed Service Identity Client. +package msi + +// Copyright (c) Microsoft and contributors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +import ( + "github.com/Azure/go-autorest/autorest" +) + +const ( + // DefaultBaseURI is the default URI used for the service Msi + DefaultBaseURI = "https://management.azure.com" +) + +// BaseClient is the base client for Msi. +type BaseClient struct { + autorest.Client + BaseURI string + SubscriptionID string +} + +// New creates an instance of the BaseClient client. +func New(subscriptionID string) BaseClient { + return NewWithBaseURI(DefaultBaseURI, subscriptionID) +} + +// NewWithBaseURI creates an instance of the BaseClient client. +func NewWithBaseURI(baseURI string, subscriptionID string) BaseClient { + return BaseClient{ + Client: autorest.NewClientWithUserAgent(UserAgent()), + BaseURI: baseURI, + SubscriptionID: subscriptionID, + } +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi/models.go b/vendor/github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi/models.go new file mode 100644 index 000000000000..c72acd231b01 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi/models.go @@ -0,0 +1,403 @@ +package msi + +// Copyright (c) Microsoft and contributors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +import ( + "encoding/json" + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/to" + "github.com/satori/go.uuid" + "net/http" +) + +// UserAssignedIdentities enumerates the values for user assigned identities. +type UserAssignedIdentities string + +const ( + // MicrosoftManagedIdentityuserAssignedIdentities ... + MicrosoftManagedIdentityuserAssignedIdentities UserAssignedIdentities = "Microsoft.ManagedIdentity/userAssignedIdentities" +) + +// PossibleUserAssignedIdentitiesValues returns an array of possible values for the UserAssignedIdentities const type. +func PossibleUserAssignedIdentitiesValues() []UserAssignedIdentities { + return []UserAssignedIdentities{MicrosoftManagedIdentityuserAssignedIdentities} +} + +// CloudError an error response from the ManagedServiceIdentity service. +type CloudError struct { + // Error - A list of additional details about the error. + Error *CloudErrorBody `json:"error,omitempty"` +} + +// CloudErrorBody an error response from the ManagedServiceIdentity service. +type CloudErrorBody struct { + // Code - An identifier for the error. + Code *string `json:"code,omitempty"` + // Message - A message describing the error, intended to be suitable for display in a user interface. + Message *string `json:"message,omitempty"` + // Target - The target of the particular error. For example, the name of the property in error. + Target *string `json:"target,omitempty"` + // Details - A list of additional details about the error. + Details *[]CloudErrorBody `json:"details,omitempty"` +} + +// Identity describes an identity resource. +type Identity struct { + autorest.Response `json:"-"` + // ID - The id of the created identity. + ID *string `json:"id,omitempty"` + // Name - The name of the created identity. + Name *string `json:"name,omitempty"` + // Location - The Azure region where the identity lives. + Location *string `json:"location,omitempty"` + // Tags - Resource tags + Tags map[string]*string `json:"tags"` + // IdentityProperties - The properties associated with the identity. + *IdentityProperties `json:"properties,omitempty"` + // Type - The type of resource i.e. Microsoft.ManagedIdentity/userAssignedIdentities. Possible values include: 'MicrosoftManagedIdentityuserAssignedIdentities' + Type UserAssignedIdentities `json:"type,omitempty"` +} + +// MarshalJSON is the custom marshaler for Identity. +func (i Identity) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]interface{}) + if i.ID != nil { + objectMap["id"] = i.ID + } + if i.Name != nil { + objectMap["name"] = i.Name + } + if i.Location != nil { + objectMap["location"] = i.Location + } + if i.Tags != nil { + objectMap["tags"] = i.Tags + } + if i.IdentityProperties != nil { + objectMap["properties"] = i.IdentityProperties + } + if i.Type != "" { + objectMap["type"] = i.Type + } + return json.Marshal(objectMap) +} + +// UnmarshalJSON is the custom unmarshaler for Identity struct. +func (i *Identity) UnmarshalJSON(body []byte) error { + var m map[string]*json.RawMessage + err := json.Unmarshal(body, &m) + if err != nil { + return err + } + for k, v := range m { + switch k { + case "id": + if v != nil { + var ID string + err = json.Unmarshal(*v, &ID) + if err != nil { + return err + } + i.ID = &ID + } + case "name": + if v != nil { + var name string + err = json.Unmarshal(*v, &name) + if err != nil { + return err + } + i.Name = &name + } + case "location": + if v != nil { + var location string + err = json.Unmarshal(*v, &location) + if err != nil { + return err + } + i.Location = &location + } + case "tags": + if v != nil { + var tags map[string]*string + err = json.Unmarshal(*v, &tags) + if err != nil { + return err + } + i.Tags = tags + } + case "properties": + if v != nil { + var identityProperties IdentityProperties + err = json.Unmarshal(*v, &identityProperties) + if err != nil { + return err + } + i.IdentityProperties = &identityProperties + } + case "type": + if v != nil { + var typeVar UserAssignedIdentities + err = json.Unmarshal(*v, &typeVar) + if err != nil { + return err + } + i.Type = typeVar + } + } + } + + return nil +} + +// IdentityProperties the properties associated with the identity. +type IdentityProperties struct { + // TenantID - The id of the tenant which the identity belongs to. + TenantID *uuid.UUID `json:"tenantId,omitempty"` + // PrincipalID - The id of the service principal object associated with the created identity. + PrincipalID *uuid.UUID `json:"principalId,omitempty"` + // ClientID - The id of the app associated with the identity. This is a random generated UUID by MSI. + ClientID *uuid.UUID `json:"clientId,omitempty"` + // ClientSecretURL - The ManagedServiceIdentity DataPlane URL that can be queried to obtain the identity credentials. + ClientSecretURL *string `json:"clientSecretUrl,omitempty"` +} + +// Operation operation supported by the Microsoft.ManagedIdentity REST API. +type Operation struct { + // Name - The name of the REST Operation. This is of the format {provider}/{resource}/{operation}. + Name *string `json:"name,omitempty"` + // Display - The object that describes the operation. + Display *OperationDisplay `json:"display,omitempty"` +} + +// OperationDisplay the object that describes the operation. +type OperationDisplay struct { + // Provider - Friendly name of the resource provider. + Provider *string `json:"provider,omitempty"` + // Operation - The type of operation. For example: read, write, delete. + Operation *string `json:"operation,omitempty"` + // Resource - The resource type on which the operation is performed. + Resource *string `json:"resource,omitempty"` + // Description - A description of the operation. + Description *string `json:"description,omitempty"` +} + +// OperationListResult a list of operations supported by Microsoft.ManagedIdentity Resource Provider. +type OperationListResult struct { + autorest.Response `json:"-"` + // Value - A list of operations supported by Microsoft.ManagedIdentity Resource Provider. + Value *[]Operation `json:"value,omitempty"` + // NextLink - The url to get the next page of results, if any. + NextLink *string `json:"nextLink,omitempty"` +} + +// OperationListResultIterator provides access to a complete listing of Operation values. +type OperationListResultIterator struct { + i int + page OperationListResultPage +} + +// Next advances to the next value. If there was an error making +// the request the iterator does not advance and the error is returned. +func (iter *OperationListResultIterator) Next() error { + iter.i++ + if iter.i < len(iter.page.Values()) { + return nil + } + err := iter.page.Next() + if err != nil { + iter.i-- + return err + } + iter.i = 0 + return nil +} + +// NotDone returns true if the enumeration should be started or is not yet complete. +func (iter OperationListResultIterator) NotDone() bool { + return iter.page.NotDone() && iter.i < len(iter.page.Values()) +} + +// Response returns the raw server response from the last page request. +func (iter OperationListResultIterator) Response() OperationListResult { + return iter.page.Response() +} + +// Value returns the current value or a zero-initialized value if the +// iterator has advanced beyond the end of the collection. +func (iter OperationListResultIterator) Value() Operation { + if !iter.page.NotDone() { + return Operation{} + } + return iter.page.Values()[iter.i] +} + +// IsEmpty returns true if the ListResult contains no values. +func (olr OperationListResult) IsEmpty() bool { + return olr.Value == nil || len(*olr.Value) == 0 +} + +// operationListResultPreparer prepares a request to retrieve the next set of results. +// It returns nil if no more results exist. +func (olr OperationListResult) operationListResultPreparer() (*http.Request, error) { + if olr.NextLink == nil || len(to.String(olr.NextLink)) < 1 { + return nil, nil + } + return autorest.Prepare(&http.Request{}, + autorest.AsJSON(), + autorest.AsGet(), + autorest.WithBaseURL(to.String(olr.NextLink))) +} + +// OperationListResultPage contains a page of Operation values. +type OperationListResultPage struct { + fn func(OperationListResult) (OperationListResult, error) + olr OperationListResult +} + +// Next advances to the next page of values. If there was an error making +// the request the page does not advance and the error is returned. +func (page *OperationListResultPage) Next() error { + next, err := page.fn(page.olr) + if err != nil { + return err + } + page.olr = next + return nil +} + +// NotDone returns true if the page enumeration should be started or is not yet complete. +func (page OperationListResultPage) NotDone() bool { + return !page.olr.IsEmpty() +} + +// Response returns the raw server response from the last page request. +func (page OperationListResultPage) Response() OperationListResult { + return page.olr +} + +// Values returns the slice of values for the current page or nil if there are no values. +func (page OperationListResultPage) Values() []Operation { + if page.olr.IsEmpty() { + return nil + } + return *page.olr.Value +} + +// UserAssignedIdentitiesListResult values returned by the List operation. +type UserAssignedIdentitiesListResult struct { + autorest.Response `json:"-"` + // Value - The collection of userAssignedIdentities returned by the listing operation. + Value *[]Identity `json:"value,omitempty"` + // NextLink - The url to get the next page of results, if any. + NextLink *string `json:"nextLink,omitempty"` +} + +// UserAssignedIdentitiesListResultIterator provides access to a complete listing of Identity values. +type UserAssignedIdentitiesListResultIterator struct { + i int + page UserAssignedIdentitiesListResultPage +} + +// Next advances to the next value. If there was an error making +// the request the iterator does not advance and the error is returned. +func (iter *UserAssignedIdentitiesListResultIterator) Next() error { + iter.i++ + if iter.i < len(iter.page.Values()) { + return nil + } + err := iter.page.Next() + if err != nil { + iter.i-- + return err + } + iter.i = 0 + return nil +} + +// NotDone returns true if the enumeration should be started or is not yet complete. +func (iter UserAssignedIdentitiesListResultIterator) NotDone() bool { + return iter.page.NotDone() && iter.i < len(iter.page.Values()) +} + +// Response returns the raw server response from the last page request. +func (iter UserAssignedIdentitiesListResultIterator) Response() UserAssignedIdentitiesListResult { + return iter.page.Response() +} + +// Value returns the current value or a zero-initialized value if the +// iterator has advanced beyond the end of the collection. +func (iter UserAssignedIdentitiesListResultIterator) Value() Identity { + if !iter.page.NotDone() { + return Identity{} + } + return iter.page.Values()[iter.i] +} + +// IsEmpty returns true if the ListResult contains no values. +func (uailr UserAssignedIdentitiesListResult) IsEmpty() bool { + return uailr.Value == nil || len(*uailr.Value) == 0 +} + +// userAssignedIdentitiesListResultPreparer prepares a request to retrieve the next set of results. +// It returns nil if no more results exist. +func (uailr UserAssignedIdentitiesListResult) userAssignedIdentitiesListResultPreparer() (*http.Request, error) { + if uailr.NextLink == nil || len(to.String(uailr.NextLink)) < 1 { + return nil, nil + } + return autorest.Prepare(&http.Request{}, + autorest.AsJSON(), + autorest.AsGet(), + autorest.WithBaseURL(to.String(uailr.NextLink))) +} + +// UserAssignedIdentitiesListResultPage contains a page of Identity values. +type UserAssignedIdentitiesListResultPage struct { + fn func(UserAssignedIdentitiesListResult) (UserAssignedIdentitiesListResult, error) + uailr UserAssignedIdentitiesListResult +} + +// Next advances to the next page of values. If there was an error making +// the request the page does not advance and the error is returned. +func (page *UserAssignedIdentitiesListResultPage) Next() error { + next, err := page.fn(page.uailr) + if err != nil { + return err + } + page.uailr = next + return nil +} + +// NotDone returns true if the page enumeration should be started or is not yet complete. +func (page UserAssignedIdentitiesListResultPage) NotDone() bool { + return !page.uailr.IsEmpty() +} + +// Response returns the raw server response from the last page request. +func (page UserAssignedIdentitiesListResultPage) Response() UserAssignedIdentitiesListResult { + return page.uailr +} + +// Values returns the slice of values for the current page or nil if there are no values. +func (page UserAssignedIdentitiesListResultPage) Values() []Identity { + if page.uailr.IsEmpty() { + return nil + } + return *page.uailr.Value +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi/operations.go b/vendor/github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi/operations.go new file mode 100644 index 000000000000..aff009073620 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi/operations.go @@ -0,0 +1,126 @@ +package msi + +// Copyright (c) Microsoft and contributors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +import ( + "context" + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "net/http" +) + +// OperationsClient is the the Managed Service Identity Client. +type OperationsClient struct { + BaseClient +} + +// NewOperationsClient creates an instance of the OperationsClient client. +func NewOperationsClient(subscriptionID string) OperationsClient { + return NewOperationsClientWithBaseURI(DefaultBaseURI, subscriptionID) +} + +// NewOperationsClientWithBaseURI creates an instance of the OperationsClient client. +func NewOperationsClientWithBaseURI(baseURI string, subscriptionID string) OperationsClient { + return OperationsClient{NewWithBaseURI(baseURI, subscriptionID)} +} + +// List lists available operations for the Microsoft.ManagedIdentity provider +func (client OperationsClient) List(ctx context.Context) (result OperationListResultPage, err error) { + result.fn = client.listNextResults + req, err := client.ListPreparer(ctx) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.OperationsClient", "List", nil, "Failure preparing request") + return + } + + resp, err := client.ListSender(req) + if err != nil { + result.olr.Response = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "msi.OperationsClient", "List", resp, "Failure sending request") + return + } + + result.olr, err = client.ListResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.OperationsClient", "List", resp, "Failure responding to request") + } + + return +} + +// ListPreparer prepares the List request. +func (client OperationsClient) ListPreparer(ctx context.Context) (*http.Request, error) { + const APIVersion = "2015-08-31-preview" + queryParameters := map[string]interface{}{ + "api-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsGet(), + autorest.WithBaseURL(client.BaseURI), + autorest.WithPath("/providers/Microsoft.ManagedIdentity/operations"), + autorest.WithQueryParameters(queryParameters)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// ListSender sends the List request. The method will close the +// http.Response Body if it receives an error. +func (client OperationsClient) ListSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...)) +} + +// ListResponder handles the response to the List request. The method always +// closes the http.Response Body. +func (client OperationsClient) ListResponder(resp *http.Response) (result OperationListResult, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingJSON(&result), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + return +} + +// listNextResults retrieves the next set of results, if any. +func (client OperationsClient) listNextResults(lastResults OperationListResult) (result OperationListResult, err error) { + req, err := lastResults.operationListResultPreparer() + if err != nil { + return result, autorest.NewErrorWithError(err, "msi.OperationsClient", "listNextResults", nil, "Failure preparing next results request") + } + if req == nil { + return + } + resp, err := client.ListSender(req) + if err != nil { + result.Response = autorest.Response{Response: resp} + return result, autorest.NewErrorWithError(err, "msi.OperationsClient", "listNextResults", resp, "Failure sending next results request") + } + result, err = client.ListResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.OperationsClient", "listNextResults", resp, "Failure responding to next results request") + } + return +} + +// ListComplete enumerates all values, automatically crossing page boundaries as required. +func (client OperationsClient) ListComplete(ctx context.Context) (result OperationListResultIterator, err error) { + result.page, err = client.List(ctx) + return +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi/userassignedidentities.go b/vendor/github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi/userassignedidentities.go new file mode 100644 index 000000000000..06c7a49452d2 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi/userassignedidentities.go @@ -0,0 +1,496 @@ +package msi + +// Copyright (c) Microsoft and contributors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +import ( + "context" + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "net/http" +) + +// UserAssignedIdentitiesClient is the the Managed Service Identity Client. +type UserAssignedIdentitiesClient struct { + BaseClient +} + +// NewUserAssignedIdentitiesClient creates an instance of the UserAssignedIdentitiesClient client. +func NewUserAssignedIdentitiesClient(subscriptionID string) UserAssignedIdentitiesClient { + return NewUserAssignedIdentitiesClientWithBaseURI(DefaultBaseURI, subscriptionID) +} + +// NewUserAssignedIdentitiesClientWithBaseURI creates an instance of the UserAssignedIdentitiesClient client. +func NewUserAssignedIdentitiesClientWithBaseURI(baseURI string, subscriptionID string) UserAssignedIdentitiesClient { + return UserAssignedIdentitiesClient{NewWithBaseURI(baseURI, subscriptionID)} +} + +// CreateOrUpdate create or update an identity in the specified subscription and resource group. +// Parameters: +// resourceGroupName - the name of the Resource Group to which the identity belongs. +// resourceName - the name of the identity resource. +// parameters - parameters to create or update the identity +func (client UserAssignedIdentitiesClient) CreateOrUpdate(ctx context.Context, resourceGroupName string, resourceName string, parameters Identity) (result Identity, err error) { + req, err := client.CreateOrUpdatePreparer(ctx, resourceGroupName, resourceName, parameters) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "CreateOrUpdate", nil, "Failure preparing request") + return + } + + resp, err := client.CreateOrUpdateSender(req) + if err != nil { + result.Response = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "CreateOrUpdate", resp, "Failure sending request") + return + } + + result, err = client.CreateOrUpdateResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "CreateOrUpdate", resp, "Failure responding to request") + } + + return +} + +// CreateOrUpdatePreparer prepares the CreateOrUpdate request. +func (client UserAssignedIdentitiesClient) CreateOrUpdatePreparer(ctx context.Context, resourceGroupName string, resourceName string, parameters Identity) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "resourceGroupName": autorest.Encode("path", resourceGroupName), + "resourceName": autorest.Encode("path", resourceName), + "subscriptionId": autorest.Encode("path", client.SubscriptionID), + } + + const APIVersion = "2015-08-31-preview" + queryParameters := map[string]interface{}{ + "api-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/json; charset=utf-8"), + autorest.AsPut(), + autorest.WithBaseURL(client.BaseURI), + autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{resourceName}", pathParameters), + autorest.WithJSON(parameters), + autorest.WithQueryParameters(queryParameters)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// CreateOrUpdateSender sends the CreateOrUpdate request. The method will close the +// http.Response Body if it receives an error. +func (client UserAssignedIdentitiesClient) CreateOrUpdateSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// CreateOrUpdateResponder handles the response to the CreateOrUpdate request. The method always +// closes the http.Response Body. +func (client UserAssignedIdentitiesClient) CreateOrUpdateResponder(resp *http.Response) (result Identity, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated), + autorest.ByUnmarshallingJSON(&result), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + return +} + +// Delete deletes the identity. +// Parameters: +// resourceGroupName - the name of the Resource Group to which the identity belongs. +// resourceName - the name of the identity resource. +func (client UserAssignedIdentitiesClient) Delete(ctx context.Context, resourceGroupName string, resourceName string) (result autorest.Response, err error) { + req, err := client.DeletePreparer(ctx, resourceGroupName, resourceName) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "Delete", nil, "Failure preparing request") + return + } + + resp, err := client.DeleteSender(req) + if err != nil { + result.Response = resp + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "Delete", resp, "Failure sending request") + return + } + + result, err = client.DeleteResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "Delete", resp, "Failure responding to request") + } + + return +} + +// DeletePreparer prepares the Delete request. +func (client UserAssignedIdentitiesClient) DeletePreparer(ctx context.Context, resourceGroupName string, resourceName string) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "resourceGroupName": autorest.Encode("path", resourceGroupName), + "resourceName": autorest.Encode("path", resourceName), + "subscriptionId": autorest.Encode("path", client.SubscriptionID), + } + + const APIVersion = "2015-08-31-preview" + queryParameters := map[string]interface{}{ + "api-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsDelete(), + autorest.WithBaseURL(client.BaseURI), + autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{resourceName}", pathParameters), + autorest.WithQueryParameters(queryParameters)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// DeleteSender sends the Delete request. The method will close the +// http.Response Body if it receives an error. +func (client UserAssignedIdentitiesClient) DeleteSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// DeleteResponder handles the response to the Delete request. The method always +// closes the http.Response Body. +func (client UserAssignedIdentitiesClient) DeleteResponder(resp *http.Response) (result autorest.Response, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusNoContent), + autorest.ByClosing()) + result.Response = resp + return +} + +// Get gets the identity. +// Parameters: +// resourceGroupName - the name of the Resource Group to which the identity belongs. +// resourceName - the name of the identity resource. +func (client UserAssignedIdentitiesClient) Get(ctx context.Context, resourceGroupName string, resourceName string) (result Identity, err error) { + req, err := client.GetPreparer(ctx, resourceGroupName, resourceName) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "Get", nil, "Failure preparing request") + return + } + + resp, err := client.GetSender(req) + if err != nil { + result.Response = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "Get", resp, "Failure sending request") + return + } + + result, err = client.GetResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "Get", resp, "Failure responding to request") + } + + return +} + +// GetPreparer prepares the Get request. +func (client UserAssignedIdentitiesClient) GetPreparer(ctx context.Context, resourceGroupName string, resourceName string) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "resourceGroupName": autorest.Encode("path", resourceGroupName), + "resourceName": autorest.Encode("path", resourceName), + "subscriptionId": autorest.Encode("path", client.SubscriptionID), + } + + const APIVersion = "2015-08-31-preview" + queryParameters := map[string]interface{}{ + "api-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsGet(), + autorest.WithBaseURL(client.BaseURI), + autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{resourceName}", pathParameters), + autorest.WithQueryParameters(queryParameters)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// GetSender sends the Get request. The method will close the +// http.Response Body if it receives an error. +func (client UserAssignedIdentitiesClient) GetSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// GetResponder handles the response to the Get request. The method always +// closes the http.Response Body. +func (client UserAssignedIdentitiesClient) GetResponder(resp *http.Response) (result Identity, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingJSON(&result), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + return +} + +// ListByResourceGroup lists all the userAssignedIdentities available under the specified ResourceGroup. +// Parameters: +// resourceGroupName - the name of the Resource Group to which the identity belongs. +func (client UserAssignedIdentitiesClient) ListByResourceGroup(ctx context.Context, resourceGroupName string) (result UserAssignedIdentitiesListResultPage, err error) { + result.fn = client.listByResourceGroupNextResults + req, err := client.ListByResourceGroupPreparer(ctx, resourceGroupName) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "ListByResourceGroup", nil, "Failure preparing request") + return + } + + resp, err := client.ListByResourceGroupSender(req) + if err != nil { + result.uailr.Response = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "ListByResourceGroup", resp, "Failure sending request") + return + } + + result.uailr, err = client.ListByResourceGroupResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "ListByResourceGroup", resp, "Failure responding to request") + } + + return +} + +// ListByResourceGroupPreparer prepares the ListByResourceGroup request. +func (client UserAssignedIdentitiesClient) ListByResourceGroupPreparer(ctx context.Context, resourceGroupName string) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "resourceGroupName": autorest.Encode("path", resourceGroupName), + "subscriptionId": autorest.Encode("path", client.SubscriptionID), + } + + const APIVersion = "2015-08-31-preview" + queryParameters := map[string]interface{}{ + "api-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsGet(), + autorest.WithBaseURL(client.BaseURI), + autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities", pathParameters), + autorest.WithQueryParameters(queryParameters)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// ListByResourceGroupSender sends the ListByResourceGroup request. The method will close the +// http.Response Body if it receives an error. +func (client UserAssignedIdentitiesClient) ListByResourceGroupSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// ListByResourceGroupResponder handles the response to the ListByResourceGroup request. The method always +// closes the http.Response Body. +func (client UserAssignedIdentitiesClient) ListByResourceGroupResponder(resp *http.Response) (result UserAssignedIdentitiesListResult, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingJSON(&result), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + return +} + +// listByResourceGroupNextResults retrieves the next set of results, if any. +func (client UserAssignedIdentitiesClient) listByResourceGroupNextResults(lastResults UserAssignedIdentitiesListResult) (result UserAssignedIdentitiesListResult, err error) { + req, err := lastResults.userAssignedIdentitiesListResultPreparer() + if err != nil { + return result, autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "listByResourceGroupNextResults", nil, "Failure preparing next results request") + } + if req == nil { + return + } + resp, err := client.ListByResourceGroupSender(req) + if err != nil { + result.Response = autorest.Response{Response: resp} + return result, autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "listByResourceGroupNextResults", resp, "Failure sending next results request") + } + result, err = client.ListByResourceGroupResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "listByResourceGroupNextResults", resp, "Failure responding to next results request") + } + return +} + +// ListByResourceGroupComplete enumerates all values, automatically crossing page boundaries as required. +func (client UserAssignedIdentitiesClient) ListByResourceGroupComplete(ctx context.Context, resourceGroupName string) (result UserAssignedIdentitiesListResultIterator, err error) { + result.page, err = client.ListByResourceGroup(ctx, resourceGroupName) + return +} + +// ListBySubscription lists all the userAssignedIdentities available under the specified subscription. +func (client UserAssignedIdentitiesClient) ListBySubscription(ctx context.Context) (result UserAssignedIdentitiesListResultPage, err error) { + result.fn = client.listBySubscriptionNextResults + req, err := client.ListBySubscriptionPreparer(ctx) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "ListBySubscription", nil, "Failure preparing request") + return + } + + resp, err := client.ListBySubscriptionSender(req) + if err != nil { + result.uailr.Response = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "ListBySubscription", resp, "Failure sending request") + return + } + + result.uailr, err = client.ListBySubscriptionResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "ListBySubscription", resp, "Failure responding to request") + } + + return +} + +// ListBySubscriptionPreparer prepares the ListBySubscription request. +func (client UserAssignedIdentitiesClient) ListBySubscriptionPreparer(ctx context.Context) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "subscriptionId": autorest.Encode("path", client.SubscriptionID), + } + + const APIVersion = "2015-08-31-preview" + queryParameters := map[string]interface{}{ + "api-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsGet(), + autorest.WithBaseURL(client.BaseURI), + autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/Microsoft.ManagedIdentity/userAssignedIdentities", pathParameters), + autorest.WithQueryParameters(queryParameters)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// ListBySubscriptionSender sends the ListBySubscription request. The method will close the +// http.Response Body if it receives an error. +func (client UserAssignedIdentitiesClient) ListBySubscriptionSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// ListBySubscriptionResponder handles the response to the ListBySubscription request. The method always +// closes the http.Response Body. +func (client UserAssignedIdentitiesClient) ListBySubscriptionResponder(resp *http.Response) (result UserAssignedIdentitiesListResult, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingJSON(&result), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + return +} + +// listBySubscriptionNextResults retrieves the next set of results, if any. +func (client UserAssignedIdentitiesClient) listBySubscriptionNextResults(lastResults UserAssignedIdentitiesListResult) (result UserAssignedIdentitiesListResult, err error) { + req, err := lastResults.userAssignedIdentitiesListResultPreparer() + if err != nil { + return result, autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "listBySubscriptionNextResults", nil, "Failure preparing next results request") + } + if req == nil { + return + } + resp, err := client.ListBySubscriptionSender(req) + if err != nil { + result.Response = autorest.Response{Response: resp} + return result, autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "listBySubscriptionNextResults", resp, "Failure sending next results request") + } + result, err = client.ListBySubscriptionResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "listBySubscriptionNextResults", resp, "Failure responding to next results request") + } + return +} + +// ListBySubscriptionComplete enumerates all values, automatically crossing page boundaries as required. +func (client UserAssignedIdentitiesClient) ListBySubscriptionComplete(ctx context.Context) (result UserAssignedIdentitiesListResultIterator, err error) { + result.page, err = client.ListBySubscription(ctx) + return +} + +// Update update an identity in the specified subscription and resource group. +// Parameters: +// resourceGroupName - the name of the Resource Group to which the identity belongs. +// resourceName - the name of the identity resource. +// parameters - parameters to update the identity +func (client UserAssignedIdentitiesClient) Update(ctx context.Context, resourceGroupName string, resourceName string, parameters Identity) (result Identity, err error) { + req, err := client.UpdatePreparer(ctx, resourceGroupName, resourceName, parameters) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "Update", nil, "Failure preparing request") + return + } + + resp, err := client.UpdateSender(req) + if err != nil { + result.Response = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "Update", resp, "Failure sending request") + return + } + + result, err = client.UpdateResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "msi.UserAssignedIdentitiesClient", "Update", resp, "Failure responding to request") + } + + return +} + +// UpdatePreparer prepares the Update request. +func (client UserAssignedIdentitiesClient) UpdatePreparer(ctx context.Context, resourceGroupName string, resourceName string, parameters Identity) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "resourceGroupName": autorest.Encode("path", resourceGroupName), + "resourceName": autorest.Encode("path", resourceName), + "subscriptionId": autorest.Encode("path", client.SubscriptionID), + } + + const APIVersion = "2015-08-31-preview" + queryParameters := map[string]interface{}{ + "api-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/json; charset=utf-8"), + autorest.AsPatch(), + autorest.WithBaseURL(client.BaseURI), + autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{resourceName}", pathParameters), + autorest.WithJSON(parameters), + autorest.WithQueryParameters(queryParameters)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// UpdateSender sends the Update request. The method will close the +// http.Response Body if it receives an error. +func (client UserAssignedIdentitiesClient) UpdateSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// UpdateResponder handles the response to the Update request. The method always +// closes the http.Response Body. +func (client UserAssignedIdentitiesClient) UpdateResponder(resp *http.Response) (result Identity, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingJSON(&result), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + return +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi/version.go b/vendor/github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi/version.go new file mode 100644 index 000000000000..7d3f9ab50203 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi/version.go @@ -0,0 +1,30 @@ +package msi + +import "github.com/Azure/azure-sdk-for-go/version" + +// Copyright (c) Microsoft and contributors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +// UserAgent returns the UserAgent string to use when sending http.Requests. +func UserAgent() string { + return "Azure-SDK-For-Go/" + version.Number + " msi/2015-08-31-preview" +} + +// Version returns the semantic version (see http://semver.org) of the client. +func Version() string { + return version.Number +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 6c28bc4d3b04..386e56b0c81d 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -178,6 +178,14 @@ "version": "=v17.4.0", "versionExact": "v17.4.0" }, + { + "checksumSHA1": "QT7LrDyti+qDCjhxerYb8PwLfew=", + "path": "github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi", + "revision": "7971189ecf5a584b9211f2527737f94bb979644e", + "revisionTime": "2018-06-19T23:05:49Z", + "version": "v17.4.0", + "versionExact": "v17.4.0" + }, { "checksumSHA1": "igbi1podNhH6Q6u4fiSG35bWVbg=", "path": "github.com/Azure/azure-sdk-for-go/services/preview/operationalinsights/mgmt/2015-11-01-preview/operationalinsights", diff --git a/website/docs/r/user_assigned_identity.markdown b/website/docs/r/user_assigned_identity.markdown new file mode 100644 index 000000000000..9358cbac4530 --- /dev/null +++ b/website/docs/r/user_assigned_identity.markdown @@ -0,0 +1,58 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azure_user_assigned_identity" +sidebar_current: "docs-azurerm-resource-user-assigned-identity" +description: |- + Manages a new user assigned identity. +--- + +# azurerm_user_assigned_identity + +Manages a user assigned identity. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "test" { + name = "acceptanceTestResourceGroup1" + location = "eastus" +} + +resource "azurerm_user_assigned_identity" "testIdentity" { + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + + name = "search-api" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the user assigned identity. Changing this forces a + new identity to be created. + +* `resource_group_name` - (Required) The name of the resource group in which to + create the user assigned identity. + +* `location` - (Required) The location/region where the user assigned identity is + created. + +* `tags` - (Optional) A mapping of tags to assign to the resource. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The user assigned identity ID. + +* `principal_id` - Service Principal ID associated with the user assigned identity. + +## Import + +User Assigned Identitites can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_user_assigned_identity.testIdentity /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/acceptanceTestResourceGroup1/providers/Microsoft.ManagedIdentity/userAssignedIdentities/testIdentity +``` diff --git a/website/docs/r/virtual_machine.html.markdown b/website/docs/r/virtual_machine.html.markdown index a481358a2e1b..8614fc85adc7 100644 --- a/website/docs/r/virtual_machine.html.markdown +++ b/website/docs/r/virtual_machine.html.markdown @@ -446,7 +446,9 @@ resource "azurerm_virtual_machine" "test" { `identity` supports the following: -* `type` - (Required) Specifies the identity type of the virtual machine. The only allowable value is `SystemAssigned`. To enable Managed Service Identity the virtual machine extension "ManagedIdentityExtensionForWindows" or "ManagedIdentityExtensionForLinux" must also be added to the virtual machine. The Principal ID can be retrieved after the virtual machine has been created, e.g. +* `type` - (Required) Specifies the identity type of the virtual machine. Allowable values are `SystemAssigned` and `UserAssigned`. To enable Managed Service Identity the virtual machine extension "ManagedIdentityExtensionForWindows" or "ManagedIdentityExtensionForLinux" must also be added to the virtual machine. For the `SystemAssigned` identity the Principal ID can be retrieved after the virtual machine has been created. See [documentation](https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/overview) for more information. + +* `identity_ids` - (Optional) Specifies a list of user managed identity ids to be assigned to the VM. Required if `type` is `UserAssigned`. ```hcl resource "azurerm_virtual_machine" "test" { diff --git a/website/docs/r/virtual_machine_scale_set.html.markdown b/website/docs/r/virtual_machine_scale_set.html.markdown index 34e8675fcf69..ea8011c871f3 100644 --- a/website/docs/r/virtual_machine_scale_set.html.markdown +++ b/website/docs/r/virtual_machine_scale_set.html.markdown @@ -274,7 +274,9 @@ The following arguments are supported: `identity` supports the following: -* `type` - (Required) Specifies the identity type to be assigned to the scale set. The only allowable value is `SystemAssigned`. To enable Managed Service Identity (MSI) on all machines in the scale set, an extension with the type "ManagedIdentityExtensionForWindows" or "ManagedIdentityExtensionForLinux" must also be added. The scale set's Service Principal ID (SPN) can be retrieved after the scale set has been created. +* `type` - (Required) Specifies the identity type to be assigned to the scale set. Allowable values are `SystemAssigned` and `UserAssigned`. To enable Managed Service Identity (MSI) on all machines in the scale set, an extension with the type "ManagedIdentityExtensionForWindows" or "ManagedIdentityExtensionForLinux" must also be added. For the `SystemAssigned` identity the scale set's Service Principal ID (SPN) can be retrieved after the scale set has been created. See [documentation](https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/overview) for more information. + +* `identity_ids` - (Optional) Specifies a list of user managed identity ids to be assigned to the VMSS. Required if `type` is `UserAssigned`. ```hcl resource "azurerm_virtual_machine_scale_set" "test" {