-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
New resource: Automation Account/Credential/Runbook/Schedule #257
New resource: Automation Account/Credential/Runbook/Schedule #257
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @Kemyke
Thanks for opening this PR and keeping up to date with all the recent changes - apologies for the delay in taking a look at this! I've taken a look through and left some comments in-line but this is off to a good start :)
The main question I've got is around the first_run
field - I'm wondering if it'd make more sense as a data source, seeing as this could be reused in the Autoscale Settings fields too?
Thanks!
"github.com/hashicorp/terraform/helper/resource" | ||
) | ||
|
||
func TestAccAzureRMAutomationAccount_importAccoutWithFreeSku(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor can we make Accout
-> Account
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
}) | ||
} | ||
|
||
func TestAccAzureRMAutomationAccount_importAccoutWithBasicSku(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor can we make Accout
-> Account
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
ForceNew: true, | ||
}, | ||
|
||
"location": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we swap this out for "location": locationSchema()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
}, | ||
|
||
"sku": { | ||
Type: schema.TypeSet, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for newer resources we're converting things overt using List's instead of Set's - could we update this to using a List? That involves updating the type here to TypeList
, removing the Set
here and then updating the Expand/Flatten to use a List, as in this resource
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Sku: &sku, | ||
}, | ||
|
||
Name: &name, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should be able to remove the name
field here, since it's specified in the CreateOrUpdate
method below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
* `password` - (Required) The password of the Credential. | ||
|
||
* `description` - (Optional) A description for this Credential. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor could we phrase this as The username associated with this Automation Credential
to match the style of the other resources?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. You mean The description associated...
i guess :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, copy and paste fail 🤦♂️
|
||
* `account_name` - (Required) The name of the automation account in which the Runbook is created. Changing this forces a new resource to be created. | ||
|
||
* `runbook_type` - (Required) The type of the runbook - can be either`Graph`, `GraphPowerShell`, `GraphPowerShellWorkflow`, `PowerShellWorkflow`, `PowerShell` or `Script`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor can we add a space between either
and "Graph
" here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
return fmt.Errorf("Cannot parse start_time: %s", cst) | ||
} | ||
} else { | ||
starttime = computeValidStartTime(d.Get("first_run").(*schema.Set), freq) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
given this is going to be needed for a few resources - would this make more sense as a datasource? I have a feeling that in it's current form this will cause a perpetual diff?
//interval := | ||
|
||
description := d.Get("description").(string) | ||
timezone := "UTC" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we make this configurable by the user, defaulted to UTC
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, docomentation is also updated
|
||
* `frequency` - (Required) The frequency of the schedule. - can be either `OneTime`, `Day`, `Hour`, `Week`, or `Month`. | ||
|
||
* `first_run` - (Optional) If an exact start time is not suitable, it can be used to make constraints for the first run. The start time will be calculated depending on these constraints. `start_time` will override this settings if defined. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(as above) would this make more sense as a data source? 🤔
first of all, thank you for your review. I fixed the easy ones and pushed them. Now i need some time for the other comments to grasp them and i will do the modification ASAP. I will come back to you if i have questions. Thank you! |
Remove name AccountCreateOrUpdateProperties
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @Kemyke
Thanks for pushing the latest updates - I've taken a look through and left a few comments but this is looking good :)
In addition to the comments we need to add the Resource Provider Registration to be able to provision Automation resources (for users who've not already registered them by hand / through the portal). We do this automatically when Terraform runs in this file, each Resource Provider is case sensitive, but it should just be a case of adding Microsoft.Automation
to that list (which I've pulled from the Portal). Without the Resource Provider registered - users will see the error:
* azurerm_automation_account.example: automation.AccountClient#CreateOrUpdate: Failure responding to request: StatusCode=409 -- Original Error: autorest/azure: Service returned an error. Status=409 Code="MissingSubscriptionRegistration" Message="The subscription is not registered to use namespace 'Microsoft.Automation'. See https://aka.ms/rps-not-found for how to register subscriptions."
Otherwise, if we can fix the few comments I've noticed - we should be in a position to run the tests & merge this :)
Thanks!
account_name = "${azurerm_automation_account.example.name}" | ||
username = "example_user" | ||
password = "example_pwd" | ||
description = "This is an example credential" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we add in the missing }
at the end of this example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
if props := resp.CredentialProperties; props != nil { | ||
d.Set("username", props.UserName) | ||
} | ||
d.Set("password", nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if this isn't returned from the API - can we remove this line? this causes a perpetual diff in Terraform:
~ azurerm_automation_credential.example
password: "<sensitive>" => "<sensitive>" (attribute changed)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
resource "azurerm_automation_runbook" "example" { | ||
name = "Get-AzureVMTutorial" | ||
location = "${azurerm_resource_group.example.location}" | ||
resource_group_name = "${azurerm_resource_group.exmaple.name}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we update exmaple
-> example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
d.Set("description", props.Description) | ||
} | ||
|
||
d.Set("publish_content_link", nil) //publish content link is not set during Get() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from what I can see, this should be available in the response - is there a reason we're not setting this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was my first tought too but as you can see on the site you linked the publishContentLink is not listed in the example JSON. If i dump the result object of the Get it is also nil:
&automation.RunbookProperties{RunbookType:"PowerShellWorkflow", PublishContentLink:(*automation.ContentLink)(nil), State:"Published", LogVerbose:(*bool)(0xc420389168), LogProgress:(*
bool)(0xc420389169), LogActivityTrace:(*int32)(0xc42038916c), JobCount:(*int32)(0xc4203891fc), Parameters:(*map[string]*automation.RunbookParameter)(0xc4202b83c0), OutputTypes:(*[]string)(0xc4204c41e0), Draft:(*automation.RunbookDraft)(nil), ProvisioningState:"Succeeded"
, LastModifiedBy:(*string)(0xc420389260), CreationTime:(*date.Time)(0xc4204c4220), LastModifiedTime:(*date.Time)(0xc4204c4320), Description:(*string)(0xc4203891e0)}
In this case should i remove the nil association?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed, now its cleaner because it doesn't cause perpetual diff. As soon as it will be available in the response we can put it back.
"start_time": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could we add some validation to check this is at least 5 minutes in the future? we can do that with a ValidateFunc
in the Schema. Submitting a date in the past returns the following error which isn't particularly helpful:
* azurerm_automation_schedule.example: automation.ScheduleClient#CreateOrUpdate: Failure responding to request: StatusCode=400 -- Original Error: autorest/azure: Service returned an error. Status=400 Code="Unknown" Message="Unknown service error"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
account_name = "${azurerm_automation_account.example.name}" | ||
frequency = "OneTime" | ||
timezone = "Central Europe Standard Time" | ||
start_time = "2014-04-15T18:00:15-07:00" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we update the timezone on this to be +02:00
- otherwise users seeing this will get a perpetual diff:
~ azurerm_automation_schedule.example
start_time: "2017-10-16T03:00:00+02:00" => "2017-10-15T18:00:15-07:00"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also using this example it appears that seconds aren't a valid interval here - do we need to validate for that?
~ azurerm_automation_schedule.example
start_time: "2017-10-15T18:00:00+02:00" => "2017-10-15T18:00:15+02:00"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think seconds are valid in the start time. You can set the start time on the Azure Website in second accuracy so i think 18:00:05 is a valid start time for a schedule.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. I only modified the timezone in the start_time.
Yeah, maybe you are right, What if we give an even more general name like |
Hi @tombuildsstuff, i have a next question regarding the Regrdin this PR, could you take a look at the new code? Does it look good? Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @Kemyke
Thanks for the continued effort here - apologies for the delay in re-reviewing this. I've taken another look through and have left some more comments - but this is looking good 😄
Thanks!
Config: config, | ||
Check: resource.ComposeTestCheckFunc( | ||
testCheckAzureRMAutomationAccountExistsAndSku("azurerm_automation_account.test", automation.Basic), | ||
), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we update this to check the remote resource exists and then check the SKU in the state, rather than in Azure (since they should be the same, and the Import test should catch this not being set correctly in Azure):
resource.TestCheckResourceAttr(resourceName, "sku.0.name", "Basic"),
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
{ | ||
Config: config, | ||
Check: resource.ComposeTestCheckFunc( | ||
testCheckAzureRMAutomationAccountExistsAndSku("azurerm_automation_account.test", automation.Free), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(same here) - can we check the field in the state, rather than in Azure (as the Import tests do that for us)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
return fmt.Errorf("Bad: Get on automationClient: %s", err) | ||
} | ||
|
||
if resp.Sku.Name != sku { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(as above) could we remove this check and fall back to checking the state, for the reasons outlined above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
}, | ||
"description": { | ||
Type: schema.TypeString, | ||
Required: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a copy-paste bug i guess. Fixed!
return err | ||
} | ||
|
||
return fmt.Errorf("EventGrid Topic still exists:\n%#v", resp) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor EventGrid Topic
-> Automation Credential
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
cst := d.Get("start_time").(string) | ||
starttime, tperr := time.Parse(time.RFC3339, cst) | ||
if tperr != nil { | ||
return fmt.Errorf("Cannot parse start_time: %s", cst) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we update this formatting argument to be %q
to quote it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
if v, ok := d.GetOk("timezone"); ok { | ||
timezone = v.(string) | ||
} else { | ||
timezone = "UTC" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we update the schema to set Default: "UTC"
? That would allow us to just get this via d.Get()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
return nil | ||
} | ||
|
||
return fmt.Errorf("Error making Read request on AzureRM Automation Schedule '%s': %s", name, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor can we make the secondary formatting argument %+v
to return the full error here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
d.Set("account_name", accName) | ||
d.Set("frequency", resp.Frequency) | ||
d.Set("description", resp.Description) | ||
d.Set("start_time", string(resp.StartTime.Format(time.RFC3339))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a reason we're not setting all the fields (such as timezone
) here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, i just forgot to add that line. And the expiry time was also missing. I didn't even set the exipry time on the CreateOrUpdateProperties, i fixed that too.
{ | ||
Config: config, | ||
Check: resource.ComposeTestCheckFunc( | ||
testCheckAzureRMAutomationScheduleExistsAndFrequencyType("azurerm_automation_schedule.test", automation.OneTime), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(as above) - can we update this to be testCheckAzureRMAutomationScheduleExists
and check the values in the state?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
can you please review the modifications? There is only one open quiestion, regarding the import_arm_automation_schedule_test. Thanks! |
Hey @Kemyke Sorry for the delay getting back to you here - I've replied in-line about that issue, but a custom DiffSuppressFunc should solve that for us :) Thanks! |
i implemented a Please check the new code! Thanks for the review! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @Kemyke
Thanks for the continued effort on this PR - I've taken a look through and this LGTM :)
There's a couple of minor things which need doing to get this merged, but I'll take care of them now:
- Vendoring the Azure SDK using
govendor
(rather than just coping the files in - Fixing the broken build (I caused this through a bad rebase, apologies)
I'll push updates for each of those shortly - but this otherwise LGTM :)
Thanks!
Also swapping the re-initialisation of `sender` to use the shared variable
Hi @tombuildsstuff , wow that's a really good news. I will create the next PR, with the In the meanwhile, as a contributor in the Azure Go SDK, there was an issue there (Azure/azure-sdk-for-go#725) which implies a bug report in the azure rest api spec project but that bug is a little bit stucked (Azure/azure-rest-api-specs#1545), don't you have influence to move that issue on a bit? Because it is immposible to create a peroidic schedule without that fix. Thanks! |
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 👉 hashibot-feedback@hashicorp.com. Thanks! |
This PR contains the minimal required resources to create and schedule an automated runbook. The automation account is the container of the credential, runbook, and schedule.
You can set the content URI for your runbook to create from. I couldn't find any way to create runbook from inline script.
Currently only OneTime schedule is creatable due to this bug in azure rest api spec (Azure/azure-rest-api-specs#1545). The Interval field cannot be set in the Go SDK so recurring schedule cannot be constructed.
The StartTime is a tricky field in the schedule because only future time is acceptable (at least 5 minutes from now). It is only control the first run of the job, the next runs will occure regarding of the interval. So i didn't use the StartTime directly in the terraform schema but i introduced a first_run object where you can set when to run first. This way you don't have to set an exact date but you can control in which hour/minute/day/... you want the job to run first. The script will calculate the first possible start time from these fields.
I will attach the documentation soon where i will show you examples. But first i want to show the code to review.Pushed.