Skip to content
This repository has been archived by the owner on Jul 26, 2021. It is now read-only.

Add datasource cloudstack_template #21

Merged
merged 3 commits into from
Nov 17, 2017

Conversation

cryptobioz
Copy link
Contributor

This datasource allows you to retrieve a template according to filters you set.
There can be several versions for one template, the datasource will always returns the most recent one.

Parameters:

If you set a filter, the datasource will only returns templates where the field name has the value value (the value can be a regex).
To see the list of available options, check the Template struct of the Cloudstack client : https://godoc.org/github.com/xanzy/go-cloudstack/cloudstack#Template

Example:

data "cloudstack_template" "my_template" {
    templatefilter = "featured"
    filter {
        name = "name"
        value = "CentOS 7\\.1"
    }
    filter {
        name = "hypervisor"
        value = "KVM"
    }
}

Note:

At the moment, filters only work with string fields, you will not be able to set options like size, tags or bootable.

Copy link
Member

@svanharmelen svanharmelen left a comment

Choose a reason for hiding this comment

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

Thanks for this one @cryptobioz! I do have a few comments we should look at first, but this will make a nice addition to the provider! 👍

for k, t := range templates {
created, err := time.Parse("2006-01-02T15:04:05-0700", t.Created)
if err != nil {
panic(err)
Copy link
Member

Choose a reason for hiding this comment

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

Please do not panic here. You should never panic, but instead just return the error. So mostRecentTemplate should then return (*cloudstack.Template, error)...

Read: dataSourceCloudstackTemplateRead,
Schema: map[string]*schema.Schema{
"filter": dataSourceFiltersSchema(),
"templatefilter": {
Copy link
Member

Choose a reason for hiding this comment

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

In TF resources the schema attributes are usually written using snake case. So templatefilter should be template_filter instead.

Type: schema.TypeString,
Computed: true,
},
"displaytext": {
Copy link
Member

Choose a reason for hiding this comment

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

This should be display_text


func dataSourceCloudstackTemplateRead(d *schema.ResourceData, meta interface{}) error {
cs := meta.(*cloudstack.CloudStackClient)
ltp := cloudstack.ListTemplatesParams{}
Copy link
Member

Choose a reason for hiding this comment

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

nitting In other places within this provider we just call the param struct p instead of in this case ltp. And please insert a blank line between line 62 and 63 for readability 😉

ltp := cloudstack.ListTemplatesParams{}
ltp.SetListall(true)
ltp.SetTemplatefilter(d.Get("templatefilter").(string))
csTemplates, err := cs.Template.ListTemplates(&ltp)
Copy link
Member

Choose a reason for hiding this comment

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

nitting Please insert a blank line between line 64 and 65 for readability

func dataSourceFiltersSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Copy link
Member

Choose a reason for hiding this comment

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

Why make this optional? I assume this call is useless without a filter right? So I suggest making this required instead.

}

func templateDescriptionAttributes(d *schema.ResourceData, template *cloudstack.Template) error {
d.SetId(template.Id)
Copy link
Member

Choose a reason for hiding this comment

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

Is this needed for a data source? To set the ID?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You have to put an ID on a datasource. I chose to use the template ID like in the datasource aws_ami.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, check... I wasn't sure a datasource also needed an ID. All clear then...


for _, f := range filters.List() {
m := f.(map[string]interface{})
r := regexp.MustCompile(m["value"].(string))
Copy link
Member

Choose a reason for hiding this comment

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

regexp.MustCompile generates a panic if the regex cannot compile. As this is user input we do not know upfront, we cannot be sure it will not panic. So instead please use regexp.Compile and check (and return if needed) the error.

m := f.(map[string]interface{})
r := regexp.MustCompile(m["value"].(string))
templateField := templateJSON[m["name"].(string)].(string)
if !r.Match([]byte(templateField)) {
Copy link
Member

Choose a reason for hiding this comment

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

Maybe r.MatchString is a better fit here?

}

return templates[mrt]
}
Copy link
Member

Choose a reason for hiding this comment

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

Another suggestion...

func mostRecentTemplate(templates []*cloudstack.Template) (*cloudstack.Template, error) {
  var latest *time.Time
  var template *cloudstack.Template

  for _, t := range templates {
    created, err := time.Parse("2006-01-02T15:04:05-0700", t.Created)
    if err != nil {
      return nil, err
    }

    if latest == nil || created.After(latest) {
      latest = created
      template = t
    }
  }

  return template, nil
 }

@cryptobioz
Copy link
Contributor Author

Thanks for the review, I made the requested changes.

@svanharmelen
Copy link
Member

There is still a small part that I would like to change/improve to make it a bit more idiomatic Go (using if..else is really discouraged in Go).

But overall it looks good now, so I'm going to merge this as is and then add a few small tweaks/fixes. Thanks again for the work!

@svanharmelen svanharmelen merged commit 5b5a218 into xanzy:master Nov 17, 2017
@svanharmelen
Copy link
Member

@cryptobioz see this commit for my additional changes: 1ca338f

One more thing I totally forgot about is the documentation or this new data source! Would/could you please open a new PR with some docs (doesn't have to be much) to go with this data source?

That would be awesome and is of course needed to make people aware of the fact that this data source now exists 😉 Thx!

@cryptobioz
Copy link
Contributor Author

I'm sorry that you had to rewrite almost everything, however, it's very instructive.
I'll open a new PR to add documentation to this datasource.
Thanks for your time and for the merge!

@svanharmelen
Copy link
Member

Don't be sorry! I only tweaked the style a bit, the logic is still all you 👍

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants