Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[MS] Adding support for Image Resources and Custom Images with Managed Disks #8

Merged
merged 11 commits into from
Jul 19, 2017
Merged

Conversation

echuvyrov
Copy link
Contributor

Support for Image ARM Resource and Custom Images with Managed Disks (porting from v0.9.8)

Copy link
Contributor

@tombuildsstuff tombuildsstuff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @echuvyrov

Thanks for pushing those updates and porting this over to the new repo - I've reviewed and left some comments in-line but this is looking good :)

Thanks!

return nil
}

var testAccAzureRMImage_standaloneImage_setup = `
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in newer resources, we're switching these for functions which return the formatted strings - can we update this to match?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

var testAccAzureRMImage_standaloneImage_setup = `
resource "azurerm_resource_group" "test" {
name = "acctestRG-%[1]d"
location = "West Central US"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for consistency, could we keep all of these resources in West US?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

var testAccAzureRMImage_standaloneImage_provision = `
resource "azurerm_resource_group" "test" {
name = "acctestRG-%[1]d"
location = "West Central US"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for consistency, could we keep all of these resources in West US?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

ConflictsWith: []string{"os_disk_os_type"},
},

"os_disk_os_type": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it worth placing these fields in an os_disk hash to match data_disk / the other resources?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


"os_disk_size_gb": {
Type: schema.TypeInt,
Optional: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this also be Computed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* `os_disk_blob_uri` - (Optional) Specifies the URI in Azure storage of the blob that you want to use to create the image.
* `os_disk_caching` - (Optional) Specifies the caching mode as 'readonly', 'readwrite', or 'none'. The default is none.
* `os_disk_size_gb` - (Optional) Specifies the size of the image to be created. The target size can't be smaller than the source size.
* `data_disk` - (Optional) The properties of the data images that
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'd tend to phrase this "One or more data_disk elements as defined below"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

the image. Changing this forces a new resource to be created.
* `location` - (Required) Specified the supported Azure location where the resource exists.
Changing this forces a new resource to be created.
* `source_virtual_machine_id` - (Required when creating image from existing VM)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'd tend to phrase this as:

* `source_virtual_machine_id` - (Optional) The Virtual Machine ID from which to create the image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried to match your style there as well

* `source_virtual_machine_id` - (Required when creating image from existing VM)
ID of an existing VM from which the image
will be created. VM must be generalized prior to creating image.
* `os_disk_os_type` - (Required) Specifies the type of operating system contained in the the virtual machine image. Possible values are: Windows or Linux.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as above: can we split this out into an os_disk block?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

password := "Password1234!"
hostName := "tftestcustomimagesrc"
dnsName := fmt.Sprintf("%[1]s.westcentralus.cloudapp.azure.com", hostName)
sshPort := "22"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can safely default this field within the testGeneralizeVMImage function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we could. I missed the random seed needed to avoid collisions between host names initially, but now that I put it in, the random seed is needed to generalize the VM since the DNS Name is one of the params to that function now. Open to different ideas here as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true, however we should be able to pass in only the username, password, hostname and region - as we can infer the rest from that?

ssh.Password(password),
},
//line below for the newer versions of SSH Client
//HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we remove this line for the moment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@echuvyrov
Copy link
Contributor Author

@tombuildsstuff I refactored the dnsName out of individual funcs, let me know if these changes look good to you.

@YuriyKishchenko
Copy link
Contributor

Hi @echuvyrov
Could you please apply the same changes to the virtual_machine_scale_set as many parts seems to be copied from virtual_machine and image uri is also applicable here.

@echuvyrov
Copy link
Contributor Author

Hi @YuriyKischenko - that's the plan :)! I wanted to split the work into smaller chunks, but VMSS support is right behind. I don't think it'll be nearly as much work, since the Image resource would be already done.

Copy link
Contributor

@tombuildsstuff tombuildsstuff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @echuvyrov

Apologies for the delay in reviewing this!

Thanks for the continued effort here - I've taken another look and left some comments in-line. The biggest issue I see is around changing the Hash's, which may require a State Migration given the underlying value has changed?

Thanks!

"source_virtual_machine_id": {
Type: schema.TypeString,
Optional: true,
ConflictsWith: []string{"os_disk.os_type"},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be wrong, but I don't think this syntax is supported?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used an example from virtual_machine as a reference (such as below) - let me know if I should change:

"managed_disk_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Computed: true,
ConflictsWith: []string{"storage_os_disk.vhd_uri"},
},

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this syntax isn't supported right now - it was merged in order to progress with the Managed Disks PR (with the anticipation of hashicorp/terraform#13019 being merged, but we've not had the time to clean it up yet (hence these comments)

For the moment it'd be good to remove these if possible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed


"os_type": {
Type: schema.TypeString,
Optional: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the documentation doesn't make this clear - but I think this can be Required within the optional os_disk block?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this also be ForceNew?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I made this field required, I got the following error:

"1 error(s) occurred:\n\n* resource azurerm_image: source_virtual_machine_id: ConflictsWith cannot contain Required attribute (os_disk.os_type)"}"

So I left the field as optional, but added ForceNew


"os_state": {
Type: schema.TypeString,
Optional: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the documentation doesn't make this clear - but I think this can be Required within the optional os_disk block?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this also be ForceNew?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same limitation as above - conflict between "Required" and "ConflictsWith"

"caching": {
Type: schema.TypeString,
Optional: true,
Default: "None",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we make this string(compute.None)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

}
}

//either source VM or storage profile can be specified, but not both
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it worth checking this and returning an error if so?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Destroy: false,
Check: resource.ComposeTestCheckFunc(
testCheckAzureVMExists("azurerm_virtual_machine.testsource", true),
testGeneralizeVMImage(fmt.Sprintf("acctestRG-%[1]d", ri), "testsource",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: if we're only formatting a single value, there's no need for the [1] here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

}
if m["image_id"] != nil {
buf.WriteString(fmt.Sprintf("%s-", m["image_id"].(string)))
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this is changing the value of the hash, is this going to need a state migration?

result["publisher"] = *image.Publisher
result["sku"] = *image.Sku

if image.Publisher != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(same) if this is changing the value of the hash - is this going to need a state migration?

offer := storageImageRef["offer"].(string)
sku := storageImageRef["sku"].(string)
version := storageImageRef["version"].(string)
if storageImageRef["image_id"] != "" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it'd probably be better for us to error on both being set?

Sku: &sku,
Version: &version,
}, nil
if imageReference.ID != nil && imageReference.Publisher != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(oh) can we move this above? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@echuvyrov
Copy link
Contributor Author

Hi @tombuildsstuff, I made all the changes requested, except for state migration recommendation. I think I need to understand this better - in my mind, I don't think we need state migration since we have a custom hash function. This custom hash function should not change the hash value for existing resources, since the fields for publisher, offer, sku, version should still all be present for non-custom images. Would appreciate you clarifying the thoughts behind the need for state migration please.

Here's the validation I performed for state, let me know if any of those are incorrect:
-Downloaded current public release of TF (0.9.9) and created basic VM + managed disk config (no custom image). Ran 'terraform plan' and the plan is showing what I expected to see. Ran 'terraform apply' to provision infra and persist state.
-Compiled terraform 0.10.0-dev with my changes. Ran 'terraform plan' on the same config - no changes detected, as expected.
-Changed sku in the config, 'terraform plan' shows 1 resource to destroy, 1 to create. As expected, since OS type has 'ForceNew' on it.
-Added the new image resource and changed VM config to use that image resource with custom image. 'terraform plan' shows 3 resources to create, 1 to destroy. I am not sure why 3, since I was expecting just 2 (1 image, 1 VM), but I am not sure if this has to do with hashing/state migration.

Thanks a ton as always!

@tombuildsstuff tombuildsstuff dismissed their stale review July 4, 2017 16:35

re-reviewing

Copy link
Contributor

@tombuildsstuff tombuildsstuff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @echuvyrov

Sorry for the delay in reviewing this!

Thanks for the continued effort here - I've taken another look through and have commented on a couple of minor issues - but this is looking good :)

Thanks!

"source_virtual_machine_id": {
Type: schema.TypeString,
Optional: true,
ConflictsWith: []string{"os_disk.os_type"},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this syntax isn't supported right now - it was merged in order to progress with the Managed Disks PR (with the anticipation of hashicorp/terraform#13019 being merged, but we've not had the time to clean it up yet (hence these comments)

For the moment it'd be good to remove these if possible?


"blob_uri": {
Type: schema.TypeString,
Optional: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this also computed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it should be - same as blob_uri for os_disk above IMHO

"blob_uri": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this also computed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this should be computed, if I understood the "Computed" property correctly. In the Developer's guide, "any Resource or Data Source property that should be stored in state but that the user should not be able to configure should have its Computed property set to true."

Per API spec here blobUri "specifies the URI in Azure storage of the blob that you want to use to create the virtual machine image" which indicates it should be changeable by the user.

"caching": {
Type: schema.TypeString,
Optional: true,
Default: "None",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this also computed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it should be - "You can specify the caching mode of the disks as readonly, readwrite, or none, by adding hostCaching. The default is none." Unless I misunderstood the Computed property of course :)


"size_gb": {
Type: schema.TypeInt,
Optional: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this also computed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it should be - "you can resize an operating system disk or the data disk in the virtual machine image as you create it by adding diskSizeGB." Unless I misunderstood the Computed property of course :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so by Computed I mean we will store the remote value in the state regardless of whether it's specified or not (but it depends if it's retuned from the API) :)


if managedDiskID != "" {
managedDisk := &compute.SubResource{}
managedDisk.ID = &managedDiskID
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we combine these two lines?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

@@ -96,21 +96,27 @@ func resourceArmVirtualMachine() *schema.Resource {
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"image_id": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 whilst I'm not opposed to this - would it make more sense to call this id to match the API Documentation / ARM Template?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

imageID := storageImageRef["image_id"].(string)
imageReference = compute.ImageReference{
ID: &imageID,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could simplify this to use the existing imageReference object defined above:

if v, ok := storageImageRef["image_id"]; ok {
  imageReference.ID = azure.String(v.(string))
} else {
 ..
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

@@ -174,6 +174,15 @@
</ul>
</li>

<li<%= sidebar_current("docs-azurerm-resource-image") %>>
<a href="#">Image Resources</a>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it worth placing this in the storage sub-section?

related: I think we should probably reorganise the sidebar in general

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put it under "Managed Disk" to match the sidebar here, hope that's Ok; agree that we should do a bit of re-organization of the side bar

Changing this forces a new resource to be created.
* `source_virtual_machine_id` - (Optional) The Virtual Machine ID from which to create the image.
* `os_disk` - (Optional) One or more os_disk elements as defined below.
* `data_disk` - (Optional) One or more data_disk elements as defined below.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we'd normally wrap this in quote's: One or more `data_disk` elements as defined below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

@echuvyrov
Copy link
Contributor Author

Hey @tombuildsstuff I made the blob_uri, caching and size_gb properties computed and made the tests pass again :). Let me know if the changes look good to you - thanks!

Copy link
Contributor

@tombuildsstuff tombuildsstuff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @echuvyrov

Thanks for pushing those updates - I've noticed (and pushed a fix for) a couple of minor issues - but this LGTM! :)

Thanks!

* `lun` - (Required) Specifies the logical unit number of the data disk.
* `managed_disk_id` - (Optional) Specifies the ID of the managed disk resource that you want to use to create the image.
* `blob_uri` - (Optional) Specifies the URI in Azure storage of the blob that you want to use to create the image.
* `caching` - (Optional) Specifies the caching mode as readonly, readwrite, or none. The default is none.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we tend to put quotes around these values, and match the casing in Azure, e.g. ReadWrite - can we update this to match?

* `os_state` - (Required) Specifies the state of the operating system contained in the blob. Currently, the only value is Generalized.
* `managed_disk_id` - (Optional) Specifies the ID of the managed disk resource that you want to use to create the image.
* `blob_uri` - (Optional) Specifies the URI in Azure storage of the blob that you want to use to create the image.
* `caching` - (Optional) Specifies the caching mode as 'readonly', 'readwrite', or 'none'. The default is none.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we tend to put quotes around these values, and match the casing in Azure, e.g. ReadWrite - can we update this to match?

os_disk_os_type = "Linux"
os_disk_os_state = "Generalized"
os_disk_blob_uri = "{blob_uri}"
os_disk_size_gb = 30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we update this example, as os_disk is now a block rather than a prefix for these fields :)

}

if resp.StatusCode != http.StatusNotFound {
return fmt.Errorf("Managed Disk still exists: \n%#v", resp.Properties)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Managed Disk -> Managed Image

@tombuildsstuff
Copy link
Contributor

Tests pass (ignoring a subscription-specific test failure):
screen shot 2017-07-19 at 13 33 56
screen shot 2017-07-19 at 13 34 00

@tombuildsstuff tombuildsstuff merged commit ed3a1a3 into hashicorp:master Jul 19, 2017
tombuildsstuff added a commit that referenced this pull request Jul 19, 2017
tombuildsstuff pushed a commit that referenced this pull request Oct 5, 2017
@ghost
Copy link

ghost commented Apr 1, 2020

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. If you feel I made an error 🤖 🙉 , please reach out to my human friends 👉 [email protected]. Thanks!

@ghost ghost locked and limited conversation to collaborators Apr 1, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants