github.com/hashicorp/terraform-plugin-sdk@v1.17.2/internal/configs/provisioner.go (about)

     1  package configs
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/hcl/v2"
     7  )
     8  
     9  // Provisioner represents a "provisioner" block when used within a
    10  // "resource" block in a module or file.
    11  type Provisioner struct {
    12  	Type       string
    13  	Config     hcl.Body
    14  	Connection *Connection
    15  	When       ProvisionerWhen
    16  	OnFailure  ProvisionerOnFailure
    17  
    18  	DeclRange hcl.Range
    19  	TypeRange hcl.Range
    20  }
    21  
    22  func decodeProvisionerBlock(block *hcl.Block) (*Provisioner, hcl.Diagnostics) {
    23  	pv := &Provisioner{
    24  		Type:      block.Labels[0],
    25  		TypeRange: block.LabelRanges[0],
    26  		DeclRange: block.DefRange,
    27  		When:      ProvisionerWhenCreate,
    28  		OnFailure: ProvisionerOnFailureFail,
    29  	}
    30  
    31  	content, config, diags := block.Body.PartialContent(provisionerBlockSchema)
    32  	pv.Config = config
    33  
    34  	if attr, exists := content.Attributes["when"]; exists {
    35  		expr, shimDiags := shimTraversalInString(attr.Expr, true)
    36  		diags = append(diags, shimDiags...)
    37  
    38  		switch hcl.ExprAsKeyword(expr) {
    39  		case "create":
    40  			pv.When = ProvisionerWhenCreate
    41  		case "destroy":
    42  			pv.When = ProvisionerWhenDestroy
    43  		default:
    44  			diags = append(diags, &hcl.Diagnostic{
    45  				Severity: hcl.DiagError,
    46  				Summary:  "Invalid \"when\" keyword",
    47  				Detail:   "The \"when\" argument requires one of the following keywords: create or destroy.",
    48  				Subject:  expr.Range().Ptr(),
    49  			})
    50  		}
    51  	}
    52  
    53  	if attr, exists := content.Attributes["on_failure"]; exists {
    54  		expr, shimDiags := shimTraversalInString(attr.Expr, true)
    55  		diags = append(diags, shimDiags...)
    56  
    57  		switch hcl.ExprAsKeyword(expr) {
    58  		case "continue":
    59  			pv.OnFailure = ProvisionerOnFailureContinue
    60  		case "fail":
    61  			pv.OnFailure = ProvisionerOnFailureFail
    62  		default:
    63  			diags = append(diags, &hcl.Diagnostic{
    64  				Severity: hcl.DiagError,
    65  				Summary:  "Invalid \"on_failure\" keyword",
    66  				Detail:   "The \"on_failure\" argument requires one of the following keywords: continue or fail.",
    67  				Subject:  attr.Expr.Range().Ptr(),
    68  			})
    69  		}
    70  	}
    71  
    72  	var seenConnection *hcl.Block
    73  	for _, block := range content.Blocks {
    74  		switch block.Type {
    75  
    76  		case "connection":
    77  			if seenConnection != nil {
    78  				diags = append(diags, &hcl.Diagnostic{
    79  					Severity: hcl.DiagError,
    80  					Summary:  "Duplicate connection block",
    81  					Detail:   fmt.Sprintf("This provisioner already has a connection block at %s.", seenConnection.DefRange),
    82  					Subject:  &block.DefRange,
    83  				})
    84  				continue
    85  			}
    86  			seenConnection = block
    87  
    88  			//conn, connDiags := decodeConnectionBlock(block)
    89  			//diags = append(diags, connDiags...)
    90  			pv.Connection = &Connection{
    91  				Config:    block.Body,
    92  				DeclRange: block.DefRange,
    93  			}
    94  
    95  		default:
    96  			// Any other block types are ones we've reserved for future use,
    97  			// so they get a generic message.
    98  			diags = append(diags, &hcl.Diagnostic{
    99  				Severity: hcl.DiagError,
   100  				Summary:  "Reserved block type name in provisioner block",
   101  				Detail:   fmt.Sprintf("The block type name %q is reserved for use by Terraform in a future version.", block.Type),
   102  				Subject:  &block.TypeRange,
   103  			})
   104  		}
   105  	}
   106  
   107  	return pv, diags
   108  }
   109  
   110  // Connection represents a "connection" block when used within either a
   111  // "resource" or "provisioner" block in a module or file.
   112  type Connection struct {
   113  	Config hcl.Body
   114  
   115  	DeclRange hcl.Range
   116  }
   117  
   118  // ProvisionerWhen is an enum for valid values for when to run provisioners.
   119  type ProvisionerWhen int
   120  
   121  //go:generate go run golang.org/x/tools/cmd/stringer -type ProvisionerWhen
   122  
   123  const (
   124  	ProvisionerWhenInvalid ProvisionerWhen = iota
   125  	ProvisionerWhenCreate
   126  	ProvisionerWhenDestroy
   127  )
   128  
   129  // ProvisionerOnFailure is an enum for valid values for on_failure options
   130  // for provisioners.
   131  type ProvisionerOnFailure int
   132  
   133  //go:generate go run golang.org/x/tools/cmd/stringer -type ProvisionerOnFailure
   134  
   135  const (
   136  	ProvisionerOnFailureInvalid ProvisionerOnFailure = iota
   137  	ProvisionerOnFailureContinue
   138  	ProvisionerOnFailureFail
   139  )
   140  
   141  var provisionerBlockSchema = &hcl.BodySchema{
   142  	Attributes: []hcl.AttributeSchema{
   143  		{Name: "when"},
   144  		{Name: "on_failure"},
   145  	},
   146  	Blocks: []hcl.BlockHeaderSchema{
   147  		{Type: "connection"},
   148  		{Type: "lifecycle"}, // reserved for future use
   149  	},
   150  }