Skip to content

Commit

Permalink
review: code fixed
Browse files Browse the repository at this point in the history
- Made minor changes to documentation.
- Standard `errors` and `fmt` were used for custom errors.
- field `Node` was renamed to `Host`.
- field `VmTags` was renamed to `Tags`
- package `virtual_machine` was renamed to `virtualmachine`
- `driver` and `testing` were moved to `common` location
  • Loading branch information
castorsky authored and tenthirtyam committed Dec 9, 2024
1 parent 08527f1 commit b571315
Show file tree
Hide file tree
Showing 21 changed files with 442 additions and 438 deletions.
5 changes: 2 additions & 3 deletions .web-docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,8 @@ packer plugins install github.com/hashicorp/vsphere

#### Data Sources

- [vsphere-virtual_machine](/packer/integrations/hashicorp/vsphere/latest/components/data-source/vsphere-virtual_machine) -
This datasource returns name of existing virtual machine that matches all defined filters to use
it as a builder source for `vsphere-clone`.
- [vsphere-virtualmachine](/packer/integrations/hashicorp/vsphere/latest/components/data-source/vsphere-virtualmachine) -
This data source returns the name of a virtual machine that matches all defined filters.

#### Post-Processors

Expand Down
Original file line number Diff line number Diff line change
@@ -1,74 +1,73 @@
Type: `vsphere-virtual_machine`
Artifact BuilderId: `vsphere.virtual_machine`
Type: `vsphere-virtualmachine`
Artifact BuilderId: `vsphere.virtualmachine`

This datasource is able to get information about existing virtual machines from vSphere
This data source retrieves information about existing virtual machines from vSphere
and return name of one virtual machine that matches all specified filters. This virtual
machine can later be used in the vSphere Clone builder to select template.
machine can be used in the vSphere Clone builder to select a template.

## Configuration Reference

### Filters Configuration

**Optional:**

<!-- Code generated from the comments of the Config struct in datasource/virtual_machine/data.go; DO NOT EDIT MANUALLY -->
<!-- Code generated from the comments of the Config struct in datasource/virtualmachine/data.go; DO NOT EDIT MANUALLY -->

- `name` (string) - Basic filter with glob support (e.g. `nginx_basic*`). Defaults to `*`.
Using strict globs will not reduce execution time because vSphere API returns the full inventory.
But can be used for better readability over regular expressions.

- `name_regex` (string) - Extended name filter with regular expressions support (e.g. `nginx[-_]basic[0-9]*`). Default is empty.
The match of the regular expression is checked by substring. Use `^` and `$` to define a full string.
E.g. the `^[^_]+$` filter will search names without any underscores.
For example, the `^[^_]+$` filter will search names without any underscores.
The expression must use [Go Regex Syntax](https://pkg.go.dev/regexp/syntax).

- `template` (bool) - Filter to return only objects that are virtual machine templates.
Defaults to `false` and returns all VMs.
Defaults to `false` and returns all virtual machines.

- `node` (string) - Filter to search virtual machines only on the specified node.
- `host` (string) - Filter to search virtual machines only on the specified ESX host.

- `vm_tags` ([]Tag) - Filter to return only that virtual machines that have attached all specifies tags.
Specify one or more `vm_tags` blocks to define list of tags that will make up the filter.
Should work since vCenter 6.7. To avoid incompatibility, REST client is being
initialized only when at least one tag has been defined in the config.
- `tags` ([]Tag) - Filter to return only that virtual machines that have attached all specifies tags.
Specify one or more `tags` blocks to define list of tags for the filter.

- `latest` (bool) - This filter determines how to handle multiple machines that were matched with all
previous filters. Machine creation time is being used to find latest.
By default, multiple matching machines results in an error.

<!-- End of code generated from the comments of the Config struct in datasource/virtual_machine/data.go; -->
<!-- End of code generated from the comments of the Config struct in datasource/virtualmachine/data.go; -->


### Tags Filter Configuration

<!-- Code generated from the comments of the Tag struct in datasource/virtual_machine/data.go; DO NOT EDIT MANUALLY -->
<!-- Code generated from the comments of the Tag struct in datasource/virtualmachine/data.go; DO NOT EDIT MANUALLY -->

Example of multiple vm_tags blocks in HCL format:
```
HCL Example:

```hcl
vm_tags {
tags {
category = "team"
name = "operations"
}
vm_tags {
category = "SLA"
tags {
category = "sla"
name = "gold"
}
```

<!-- End of code generated from the comments of the Tag struct in datasource/virtual_machine/data.go; -->
<!-- End of code generated from the comments of the Tag struct in datasource/virtualmachine/data.go; -->


**Required:**

<!-- Code generated from the comments of the Tag struct in datasource/virtual_machine/data.go; DO NOT EDIT MANUALLY -->
<!-- Code generated from the comments of the Tag struct in datasource/virtualmachine/data.go; DO NOT EDIT MANUALLY -->

- `name` (string) - Tag with this name must be attached to virtual machine which should pass the Tags Filter.

- `category` (string) - Name of the category that contains this tag. Both tag and category must be specified.

<!-- End of code generated from the comments of the Tag struct in datasource/virtual_machine/data.go; -->
<!-- End of code generated from the comments of the Tag struct in datasource/virtualmachine/data.go; -->


### Connection Configuration
Expand Down Expand Up @@ -100,48 +99,47 @@ Example of multiple vm_tags blocks in HCL format:

## Output

<!-- Code generated from the comments of the DatasourceOutput struct in datasource/virtual_machine/data.go; DO NOT EDIT MANUALLY -->
<!-- Code generated from the comments of the DatasourceOutput struct in datasource/virtualmachine/data.go; DO NOT EDIT MANUALLY -->

- `vm_name` (string) - Name of the found virtual machine.

<!-- End of code generated from the comments of the DatasourceOutput struct in datasource/virtual_machine/data.go; -->
<!-- End of code generated from the comments of the DatasourceOutput struct in datasource/virtualmachine/data.go; -->


## Example Usage

This is a very basic example that connects to vSphere cluster and tries to search
the latest virtual machine that matches all filters. The machine name is then printed
to console as output variable.
This example demonstrates how to connect to vSphere cluster and search for the latest virtual machine
that matches the filters. The name of the machine is then output to the console as an output variable.
```hcl
data "vsphere-virtual_machine" "default" {
vcenter_server = "vcenter.example.org"
data "vsphere-virtualmachine" "default" {
vcenter_server = "vcenter.example.com"
insecure_connection = true
username = "administrator@example.org"
password = "St4ongPa$$w0rd"
datacenter = "AZ1"
username = "administrator@vsphere.local"
password = "VMware1!"
datacenter = "dc-01"
latest = true
vm_tags {
tags {
category = "team"
name = "operations"
}
vm_tags {
category = "SLA"
tags {
category = "sla"
name = "gold"
}
}
locals {
vm_name = data.vsphere-virtual_machine.default.vm_name
vm_name = data.vsphere-virtualmachine.default.vm_name
}
source "null" "basic-example" {
source "null" "example" {
communicator = "none"
}
build {
sources = [
"source.null.basic-example"
"source.null.example"
]
provisioner "shell-local" {
Expand All @@ -150,6 +148,4 @@ build {
]
}
}
```
2 changes: 1 addition & 1 deletion .web-docs/metadata.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ integration {
component {
type = "data-source"
name = "vSphere Virtual Machine"
slug = "vsphere-virtual_machine"
slug = "vsphere-virtualmachine"
}
}
1 change: 0 additions & 1 deletion builder/vsphere/driver/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,6 @@ func (vm *VirtualMachineDriver) Clone(ctx context.Context, config *CloneConfig)
Device: adapter.(types.BaseVirtualDevice),
Operation: types.VirtualDeviceConfigSpecOperationEdit,
}

configSpec.DeviceChange = append(configSpec.DeviceChange, config)
}

Expand Down
60 changes: 60 additions & 0 deletions datasource/common/driver/driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package driver

import (
"context"
"fmt"
"net/url"

"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common"
"github.com/vmware/govmomi"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vapi/rest"
)

type VCenterDriver struct {
Ctx context.Context
Client *govmomi.Client
RestClient *rest.Client
Finder *find.Finder
Datacenter *object.Datacenter
}

func NewDriver(config common.ConnectConfig) (*VCenterDriver, error) {
ctx := context.Background()

vcenterUrl, err := url.Parse(fmt.Sprintf("https://%v/sdk", config.VCenterServer))
if err != nil {
return nil, fmt.Errorf("failed to parse URL: %w", err)
}
vcenterUrl.User = url.UserPassword(config.Username, config.Password)

client, err := govmomi.NewClient(ctx, vcenterUrl, true)
if err != nil {
return nil, fmt.Errorf("failed to create govmomi Client: %w", err)
}

restClient := rest.NewClient(client.Client)
err = restClient.Login(ctx, vcenterUrl.User)
if err != nil {
return nil, fmt.Errorf("failed to login to REST API endpoint: %w", err)
}

finder := find.NewFinder(client.Client, true)
datacenter, err := finder.DatacenterOrDefault(ctx, config.Datacenter)
if err != nil {
return nil, fmt.Errorf("failed to find datacenter: %w", err)
}
finder.SetDatacenter(datacenter)

return &VCenterDriver{
Ctx: ctx,
Client: client,
RestClient: restClient,
Finder: finder,
Datacenter: datacenter,
}, nil
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,40 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package testing

import (
"context"
"fmt"

"github.com/pkg/errors"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vapi/tags"
)

// MarkSimulatedVmAsTemplate powers off the virtual machine before converting it to a template (because the simulator
// creates all virtual machines in an online state).
func MarkSimulatedVmAsTemplate(ctx context.Context, vm *object.VirtualMachine) error {
task, err := vm.PowerOff(ctx)
if err != nil {
return errors.Wrap(err, "failed to issue powering off command to the machine")
return fmt.Errorf("failed to issue powering off command to the machine: %w", err)
}
err = task.Wait(ctx)
if err != nil {
return errors.Wrap(err, "failed to power off the machine")
return fmt.Errorf("failed to power off the machine: %w", err)
}
err = vm.MarkAsTemplate(ctx)
if err != nil {
return errors.Wrap(err, "failed to mark VM as a template")
return fmt.Errorf("failed to mark virtual machine as a template: %w", err)
}
return nil
}

// Try to find category passed by name, create category if not found and return category ID.
// FindOrCreateCategory tries to find category passed by name, creates category if not found and returns category ID.
// Category will be created with "MULTIPLE" constraint.
func FindOrCreateCategory(ctx context.Context, man *tags.Manager, catName string) (string, error) {
categoryList, err := man.GetCategories(ctx)
if err != nil {
return "", errors.Wrap(err, "cannot get categories from cluster")
return "", fmt.Errorf("cannot return categories from cluster: %w", err)
}
for _, category := range categoryList {
if category.Name == catName {
Expand All @@ -38,16 +43,16 @@ func FindOrCreateCategory(ctx context.Context, man *tags.Manager, catName string
}
newCategoryID, err := man.CreateCategory(ctx, &tags.Category{Name: catName, Cardinality: "MULTIPLE"})
if err != nil {
return "", errors.Wrap(err, "cannot create category")
return "", fmt.Errorf("cannot create category: %w", err)
}
return newCategoryID, nil
}

// Try to find the tagName in category with catID, create if not found and return tag ID.
// FindOrCreateTag tries to find the tagName in category with catID, creates if not found and returns tag ID.
func FindOrCreateTag(ctx context.Context, man *tags.Manager, catID string, tagName string) (string, error) {
tagsInCategory, err := man.GetTagsForCategory(ctx, catID)
if err != nil {
return "", errors.Wrap(err, "cannot get tags for category")
return "", fmt.Errorf("cannot return tags for category: %w", err)
}
for _, tag := range tagsInCategory {
if tag.Name == tagName {
Expand All @@ -56,7 +61,7 @@ func FindOrCreateTag(ctx context.Context, man *tags.Manager, catID string, tagNa
}
newTagID, err := man.CreateTag(ctx, &tags.Tag{Name: tagName, CategoryID: catID})
if err != nil {
return "", errors.Wrap(err, "cannot create tag")
return "", fmt.Errorf("cannot create tag: %w", err)
}
return newTagID, nil
}
Loading

0 comments on commit b571315

Please sign in to comment.