Skip to content

Commit

Permalink
Added the ability to set environment variables for scripts (#49)
Browse files Browse the repository at this point in the history
* Adding ability to set environment vars

- Added the ability to set environment vars in the deploy resource to finetune devops service configuration

* fixed the documentation issue

* Added the ability to set environment variables for scripts

- Added the ability to set environment variables in the post processor scripts and on destroy scripts
- Fixed an issue where if a catalog was not found the provider would crash
- Improved a error message for when there is no hardware in a orchestrator that can host the remote image

* updated documentation
  • Loading branch information
cjlapao authored Oct 29, 2024
1 parent 1c40878 commit 586d57f
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 64 deletions.
2 changes: 2 additions & 0 deletions docs/resources/clone_vm.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ Optional:

Optional:

- `environment_variables` (Map of String) Environment variables that can be used in the DevOps service, please see documentation to see which variables are available
- `inline` (List of String) Inline script
- `retry` (Block, Optional) Retry settings (see [below for nested schema](#nestedblock--on_destroy_script--retry))

Expand Down Expand Up @@ -182,6 +183,7 @@ Optional:

Optional:

- `environment_variables` (Map of String) Environment variables that can be used in the DevOps service, please see documentation to see which variables are available
- `inline` (List of String) Inline script
- `retry` (Block, Optional) Retry settings (see [below for nested schema](#nestedblock--post_processor_script--retry))

Expand Down
2 changes: 2 additions & 0 deletions docs/resources/remote_vm.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ Optional:

Optional:

- `environment_variables` (Map of String) Environment variables that can be used in the DevOps service, please see documentation to see which variables are available
- `inline` (List of String) Inline script
- `retry` (Block, Optional) Retry settings (see [below for nested schema](#nestedblock--on_destroy_script--retry))

Expand Down Expand Up @@ -195,6 +196,7 @@ Optional:

Optional:

- `environment_variables` (Map of String) Environment variables that can be used in the DevOps service, please see documentation to see which variables are available
- `inline` (List of String) Inline script
- `retry` (Block, Optional) Retry settings (see [below for nested schema](#nestedblock--post_processor_script--retry))

Expand Down
2 changes: 2 additions & 0 deletions docs/resources/vagrant_box.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ Optional:

Optional:

- `environment_variables` (Map of String) Environment variables that can be used in the DevOps service, please see documentation to see which variables are available
- `inline` (List of String) Inline script
- `retry` (Block, Optional) Retry settings (see [below for nested schema](#nestedblock--on_destroy_script--retry))

Expand Down Expand Up @@ -201,6 +202,7 @@ Optional:

Optional:

- `environment_variables` (Map of String) Environment variables that can be used in the DevOps service, please see documentation to see which variables are available
- `inline` (List of String) Inline script
- `retry` (Block, Optional) Retry settings (see [below for nested schema](#nestedblock--post_processor_script--retry))

Expand Down
10 changes: 9 additions & 1 deletion internal/apiclient/apimodels/vm_execute.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
package apimodels

type PostScriptItem struct {
Command string `json:"command"`
VirtualMachineId string `json:"virtual_machine_id"`
OS string `json:"os"`
EnvironmentVariables map[string]string `json:"environment_variables,omitempty"`
}

type VmExecuteCommandRequest struct {
Command string `json:"command"`
Command string `json:"command"`
EnvironmentVariables map[string]string `json:"environment_variables,omitempty"`
}

type VmExecuteCommandResponse struct {
Expand Down
10 changes: 6 additions & 4 deletions internal/apiclient/execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,25 @@ import (
"github.com/hashicorp/terraform-plugin-log/tflog"
)

func ExecuteScript(ctx context.Context, config HostConfig, machineId string, script string) (*apimodels.VmExecuteCommandResponse, diag.Diagnostics) {
func ExecuteScript(ctx context.Context, config HostConfig, r apimodels.PostScriptItem) (*apimodels.VmExecuteCommandResponse, diag.Diagnostics) {
diagnostics := diag.Diagnostics{}
urlHost := helpers.GetHostUrl(config.Host)
var url string
if config.IsOrchestrator {
url = fmt.Sprintf("%s/orchestrator/machines/%s/execute", helpers.GetHostApiVersionedBaseUrl(urlHost), machineId)
url = fmt.Sprintf("%s/orchestrator/machines/%s/execute", helpers.GetHostApiVersionedBaseUrl(urlHost), r.VirtualMachineId)
} else {
url = fmt.Sprintf("%s/machines/%s/execute", helpers.GetHostApiVersionedBaseUrl(urlHost), machineId)
url = fmt.Sprintf("%s/machines/%s/execute", helpers.GetHostApiVersionedBaseUrl(urlHost), r.VirtualMachineId)
}

auth, err := authenticator.GetAuthenticator(ctx, urlHost, config.License, config.Authorization, config.DisableTlsValidation)
if err != nil {
diagnostics.AddError("There was an error getting the authenticator", err.Error())
return nil, diagnostics
}

request := apimodels.VmExecuteCommandRequest{
Command: script,
Command: r.Command,
EnvironmentVariables: r.EnvironmentVariables,
}

client := helpers.NewHttpCaller(ctx, config.DisableTlsValidation)
Expand Down
2 changes: 1 addition & 1 deletion internal/common/check_required_specs.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func CheckIfEnoughSpecs(ctx context.Context, hostConfig apiclient.HostConfig, sp
}
}
if !foundArchitectureResources {
diagnostics.AddError("error getting hardware info", fmt.Sprintf("error getting hardware info for %s architecture", arch))
diagnostics.AddError("Hardware", fmt.Sprintf("Did not find any hosts for %s architecture in the orchestrator, please check if you have any online", arch))
return diagnostics
}
} else {
Expand Down
8 changes: 6 additions & 2 deletions internal/common/post_processor_script.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,14 @@ func RunPostProcessorScript(ctx context.Context, hostConfig apiclient.HostConfig

if err := retry.For(maxRetries, waitBeforeRetry, func() error {
tflog.Info(ctx, fmt.Sprintf("Running post processor script %s on vm %s with state %s [%v]", script.Inline, refreshVm.Name, refreshVm.State, maxRetries))
resultDiag := script.Apply(ctx, hostConfig, refreshVm.ID)
resultDiag := script.Apply(ctx, hostConfig, vm)
tflog.Info(ctx, fmt.Sprintf("Script %s executed, result %v", script.Inline, resultDiag))
if resultDiag.HasError() {
return errors.New("script failed")
errorMessages := "Script failed to run:"
for _, diag := range resultDiag.Errors() {
errorMessages += "\n" + diag.Summary() + " " + diag.Detail()
}
return errors.New(errorMessages)
}

return nil
Expand Down
5 changes: 5 additions & 0 deletions internal/remoteimage/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ func (r *RemoteVmResource) Create(ctx context.Context, req resource.CreateReques
resp.Diagnostics.AddError("Catalog Not Found", fmt.Sprintf("Catalog %s was not found on %s", data.CatalogId.ValueString(), catalogHostConfig.Host))
return
}
// the catalog manifest is nil, we will add an error to the diagnostics
if catalogManifest == nil {
resp.Diagnostics.AddError("Catalog Not Found", fmt.Sprintf("Catalog %s was not found on %s", data.CatalogId.ValueString(), catalogHostConfig.Host))
return
}

// Checking if the VM already exists in the host
vm, diag := apiclient.GetVms(ctx, hostConfig, "Name", data.Name.String())
Expand Down
28 changes: 23 additions & 5 deletions internal/schemas/postprocessorscript/post_processor_script.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package postprocessorscript
import (
"context"
"fmt"
"strings"

"terraform-provider-parallels-desktop/internal/apiclient"
"terraform-provider-parallels-desktop/internal/apiclient/apimodels"

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
Expand All @@ -14,12 +16,13 @@ import (
)

type PostProcessorScript struct {
Inline types.List `tfsdk:"inline"`
Retry *PostProcessorScriptRetry `tfsdk:"retry"`
Result basetypes.ListValue `tfsdk:"result"`
Inline types.List `tfsdk:"inline"`
Retry *PostProcessorScriptRetry `tfsdk:"retry"`
EnvironmentVariables map[string]types.String `tfsdk:"environment_variables"`
Result basetypes.ListValue `tfsdk:"result"`
}

func (s *PostProcessorScript) Apply(ctx context.Context, config apiclient.HostConfig, vmId string) diag.Diagnostics {
func (s *PostProcessorScript) Apply(ctx context.Context, config apiclient.HostConfig, vm *apimodels.VirtualMachine) diag.Diagnostics {
diagnostic := diag.Diagnostics{}
elements := make([]attr.Value, 0)
t := PostProcessorScriptRunResult{}
Expand All @@ -38,7 +41,22 @@ func (s *PostProcessorScript) Apply(ctx context.Context, config apiclient.HostCo
return diagnostic
}

resp, resultDiagnostic := apiclient.ExecuteScript(ctx, config, vmId, stringScript)
environmentVariables := map[string]string{}

if len(s.EnvironmentVariables) > 0 {
for key, value := range s.EnvironmentVariables {
environmentVariables[key] = strings.TrimPrefix(strings.TrimSuffix(value.String(), "\""), "\"")
}
}

request := apimodels.PostScriptItem{
Command: stringScript,
EnvironmentVariables: environmentVariables,
VirtualMachineId: vm.ID,
OS: vm.OS,
}

resp, resultDiagnostic := apiclient.ExecuteScript(ctx, config, request)
if resultDiagnostic.HasError() {
tflog.Error(ctx, fmt.Sprintf("Error executing script: %v", resultDiagnostic))
diagnostic = append(diagnostic, resultDiagnostic...)
Expand Down
108 changes: 57 additions & 51 deletions internal/schemas/postprocessorscript/schemas.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,64 +5,70 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types"
)

var SchemaName = "post_processor_script"
var SchemaBlock = schema.ListNestedBlock{
MarkdownDescription: "Run any script after the virtual machine is created",
Description: "Run any script after the virtual machine is created",
NestedObject: schema.NestedBlockObject{
Blocks: map[string]schema.Block{
"retry": schema.SingleNestedBlock{
MarkdownDescription: "Retry settings",
Attributes: map[string]schema.Attribute{
"attempts": schema.Int64Attribute{
MarkdownDescription: "Number of attempts",
Optional: true,
},
"wait_between_attempts": schema.StringAttribute{
MarkdownDescription: "Wait between attempts, you can use the suffixes 's' for seconds, 'm' for minutes",
Optional: true,
},
},
},
},
Attributes: map[string]schema.Attribute{
"inline": schema.ListAttribute{
MarkdownDescription: "Inline script",
Optional: true,
Description: "Inline script",
ElementType: types.StringType,
},

"result": schema.ListNestedAttribute{
MarkdownDescription: "Result of the script",
Description: "Result of the script",
Computed: true,
Sensitive: true,
NestedObject: schema.NestedAttributeObject{
var (
SchemaName = "post_processor_script"
SchemaBlock = schema.ListNestedBlock{
MarkdownDescription: "Run any script after the virtual machine is created",
Description: "Run any script after the virtual machine is created",
NestedObject: schema.NestedBlockObject{
Blocks: map[string]schema.Block{
"retry": schema.SingleNestedBlock{
MarkdownDescription: "Retry settings",
Attributes: map[string]schema.Attribute{
"exit_code": schema.StringAttribute{
MarkdownDescription: "Exit code",
Optional: true,
Description: "Exit code",
},
"stdout": schema.StringAttribute{
MarkdownDescription: "Stdout",
"attempts": schema.Int64Attribute{
MarkdownDescription: "Number of attempts",
Optional: true,
Description: "Stdout",
},
"stderr": schema.StringAttribute{
MarkdownDescription: "Stderr",
"wait_between_attempts": schema.StringAttribute{
MarkdownDescription: "Wait between attempts, you can use the suffixes 's' for seconds, 'm' for minutes",
Optional: true,
Description: "Stderr",
},
"script": schema.StringAttribute{
MarkdownDescription: "Script",
Optional: true,
Description: "Script",
},
},
},
Attributes: map[string]schema.Attribute{
"inline": schema.ListAttribute{
MarkdownDescription: "Inline script",
Optional: true,
Description: "Inline script",
ElementType: types.StringType,
},
"environment_variables": schema.MapAttribute{
MarkdownDescription: "Environment variables that can be used in the DevOps service, please see documentation to see which variables are available",
Optional: true,
ElementType: types.StringType,
},
"result": schema.ListNestedAttribute{
MarkdownDescription: "Result of the script",
Description: "Result of the script",
Computed: true,
Sensitive: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"exit_code": schema.StringAttribute{
MarkdownDescription: "Exit code",
Optional: true,
Description: "Exit code",
},
"stdout": schema.StringAttribute{
MarkdownDescription: "Stdout",
Optional: true,
Description: "Stdout",
},
"stderr": schema.StringAttribute{
MarkdownDescription: "Stderr",
Optional: true,
Description: "Stderr",
},
"script": schema.StringAttribute{
MarkdownDescription: "Script",
Optional: true,
Description: "Script",
},
},
},
},
},
},
},
}
}
)

0 comments on commit 586d57f

Please sign in to comment.