Add checks for all flags we currently don’t support
For Plan only: -module-depth=n For Plan & Apply -parallelism=m -refresh=false -var “foo=bar” and -var-file=foo
This commit is contained in:
parent
979aa812df
commit
67db9da000
|
@ -137,11 +137,13 @@ type Operation struct {
|
|||
|
||||
// The options below are more self-explanatory and affect the runtime
|
||||
// behavior of the operation.
|
||||
AutoApprove bool
|
||||
Destroy bool
|
||||
DestroyForce bool
|
||||
ModuleDepth int
|
||||
Parallelism int
|
||||
Targets []string
|
||||
Variables map[string]interface{}
|
||||
AutoApprove bool
|
||||
DestroyForce bool
|
||||
|
||||
// Input/output/control options.
|
||||
UIIn terraform.UIInput
|
||||
|
|
|
@ -24,8 +24,10 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
defaultHostname = "app.terraform.io"
|
||||
serviceID = "tfe.v2"
|
||||
defaultHostname = "app.terraform.io"
|
||||
defaultModuleDepth = -1
|
||||
defaultParallelism = 10
|
||||
serviceID = "tfe.v2"
|
||||
)
|
||||
|
||||
// Remote is an implementation of EnhancedBackend that performs all
|
||||
|
|
|
@ -31,14 +31,27 @@ func (b *Remote) opApply(stopCtx, cancelCtx context.Context, op *backend.Operati
|
|||
return nil, fmt.Errorf(strings.TrimSpace(applyErrVCSNotSupported))
|
||||
}
|
||||
|
||||
if op.Parallelism != defaultParallelism {
|
||||
return nil, fmt.Errorf(strings.TrimSpace(applyErrParallelismNotSupported))
|
||||
}
|
||||
|
||||
if op.Plan != nil {
|
||||
return nil, fmt.Errorf(strings.TrimSpace(applyErrPlanNotSupported))
|
||||
}
|
||||
|
||||
if !op.PlanRefresh {
|
||||
return nil, fmt.Errorf(strings.TrimSpace(applyErrNoRefreshNotSupported))
|
||||
}
|
||||
|
||||
if op.Targets != nil {
|
||||
return nil, fmt.Errorf(strings.TrimSpace(applyErrTargetsNotSupported))
|
||||
}
|
||||
|
||||
if op.Variables != nil {
|
||||
return nil, fmt.Errorf(strings.TrimSpace(
|
||||
fmt.Sprintf(applyErrVariablesNotSupported, b.hostname, b.organization, op.Workspace)))
|
||||
}
|
||||
|
||||
if (op.Module == nil || op.Module.Config().Dir == "") && !op.Destroy {
|
||||
return nil, fmt.Errorf(strings.TrimSpace(applyErrNoConfig))
|
||||
}
|
||||
|
@ -96,7 +109,7 @@ func (b *Remote) opApply(stopCtx, cancelCtx context.Context, op *backend.Operati
|
|||
}
|
||||
}
|
||||
return r, fmt.Errorf(strings.TrimSpace(
|
||||
fmt.Sprint(applyErrNoApplyRights, b.hostname, b.organization, op.Workspace)))
|
||||
fmt.Sprintf(applyErrNoApplyRights, b.hostname, b.organization, op.Workspace)))
|
||||
}
|
||||
|
||||
hasUI := op.UIIn != nil && op.UIOut != nil
|
||||
|
@ -286,11 +299,25 @@ A workspace that is connected to a VCS requires the VCS-driven workflow
|
|||
to ensure that the VCS remains the single source of truth.
|
||||
`
|
||||
|
||||
const applyErrParallelismNotSupported = `
|
||||
Custom parallelism values are currently not supported!
|
||||
|
||||
The "remote" backend does not support setting a custom parallelism
|
||||
value at this time.
|
||||
`
|
||||
|
||||
const applyErrPlanNotSupported = `
|
||||
Applying a saved plan is currently not supported!
|
||||
|
||||
The "remote" backend currently requires configuration to be present
|
||||
and does not accept an existing saved plan as an argument at this time.
|
||||
The "remote" backend currently requires configuration to be present and
|
||||
does not accept an existing saved plan as an argument at this time.
|
||||
`
|
||||
|
||||
const applyErrNoRefreshNotSupported = `
|
||||
Applying without refresh is currently not supported!
|
||||
|
||||
Currently the "remote" backend will always do an in-memory refresh of
|
||||
the Terraform state prior to generating the plan.
|
||||
`
|
||||
|
||||
const applyErrTargetsNotSupported = `
|
||||
|
@ -299,6 +326,19 @@ Resource targeting is currently not supported!
|
|||
The "remote" backend does not support resource targeting at this time.
|
||||
`
|
||||
|
||||
const applyErrVariablesNotSupported = `
|
||||
Run variables are currently not supported!
|
||||
|
||||
The "remote" backend does not support setting run variables at this time.
|
||||
Currently the only to way to pass variables to the remote backend is by
|
||||
creating a '*.auto.tfvars' variables file. This file will automatically
|
||||
be loaded by the "remote" backend when the workspace is configured to use
|
||||
Terraform v0.10.0 or later.
|
||||
|
||||
Additionally you can also set variables on the workspace in the web UI:
|
||||
https://%s/app/%s/%s/variables
|
||||
`
|
||||
|
||||
const applyErrNoConfig = `
|
||||
No configuration files found!
|
||||
|
||||
|
|
|
@ -18,7 +18,9 @@ import (
|
|||
|
||||
func testOperationApply() *backend.Operation {
|
||||
return &backend.Operation{
|
||||
Type: backend.OperationTypeApply,
|
||||
Parallelism: defaultParallelism,
|
||||
PlanRefresh: true,
|
||||
Type: backend.OperationTypeApply,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,6 +137,31 @@ func TestRemote_applyWithVCS(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRemote_applyWithParallelism(t *testing.T) {
|
||||
b := testBackendDefault(t)
|
||||
|
||||
mod, modCleanup := module.TestTree(t, "./test-fixtures/apply")
|
||||
defer modCleanup()
|
||||
|
||||
op := testOperationApply()
|
||||
op.Module = mod
|
||||
op.Parallelism = 3
|
||||
op.Workspace = backend.DefaultStateName
|
||||
|
||||
run, err := b.Operation(context.Background(), op)
|
||||
if err != nil {
|
||||
t.Fatalf("error starting operation: %v", err)
|
||||
}
|
||||
<-run.Done()
|
||||
|
||||
if run.Err == nil {
|
||||
t.Fatalf("expected an apply error, got: %v", run.Err)
|
||||
}
|
||||
if !strings.Contains(run.Err.Error(), "parallelism values are currently not supported") {
|
||||
t.Fatalf("expected a parallelism error, got: %v", run.Err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemote_applyWithPlan(t *testing.T) {
|
||||
b := testBackendDefault(t)
|
||||
|
||||
|
@ -160,6 +187,31 @@ func TestRemote_applyWithPlan(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRemote_applyWithoutRefresh(t *testing.T) {
|
||||
b := testBackendDefault(t)
|
||||
|
||||
mod, modCleanup := module.TestTree(t, "./test-fixtures/apply")
|
||||
defer modCleanup()
|
||||
|
||||
op := testOperationApply()
|
||||
op.Module = mod
|
||||
op.PlanRefresh = false
|
||||
op.Workspace = backend.DefaultStateName
|
||||
|
||||
run, err := b.Operation(context.Background(), op)
|
||||
if err != nil {
|
||||
t.Fatalf("error starting operation: %v", err)
|
||||
}
|
||||
<-run.Done()
|
||||
|
||||
if run.Err == nil {
|
||||
t.Fatalf("expected an apply error, got: %v", run.Err)
|
||||
}
|
||||
if !strings.Contains(run.Err.Error(), "refresh is currently not supported") {
|
||||
t.Fatalf("expected a refresh error, got: %v", run.Err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemote_applyWithTarget(t *testing.T) {
|
||||
b := testBackendDefault(t)
|
||||
|
||||
|
@ -185,6 +237,31 @@ func TestRemote_applyWithTarget(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRemote_applyWithVariables(t *testing.T) {
|
||||
b := testBackendDefault(t)
|
||||
|
||||
mod, modCleanup := module.TestTree(t, "./test-fixtures/apply")
|
||||
defer modCleanup()
|
||||
|
||||
op := testOperationApply()
|
||||
op.Module = mod
|
||||
op.Variables = map[string]interface{}{"foo": "bar"}
|
||||
op.Workspace = backend.DefaultStateName
|
||||
|
||||
run, err := b.Operation(context.Background(), op)
|
||||
if err != nil {
|
||||
t.Fatalf("error starting operation: %v", err)
|
||||
}
|
||||
<-run.Done()
|
||||
|
||||
if run.Err == nil {
|
||||
t.Fatalf("expected an apply error, got: %v", run.Err)
|
||||
}
|
||||
if !strings.Contains(run.Err.Error(), "variables are currently not supported") {
|
||||
t.Fatalf("expected a variables error, got: %v", run.Err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemote_applyNoConfig(t *testing.T) {
|
||||
b := testBackendDefault(t)
|
||||
|
||||
|
|
|
@ -30,6 +30,14 @@ func (b *Remote) opPlan(stopCtx, cancelCtx context.Context, op *backend.Operatio
|
|||
return nil, fmt.Errorf(strings.TrimSpace(fmt.Sprintf(planErrNoQueueRunRights)))
|
||||
}
|
||||
|
||||
if op.ModuleDepth != defaultModuleDepth {
|
||||
return nil, fmt.Errorf(strings.TrimSpace(planErrModuleDepthNotSupported))
|
||||
}
|
||||
|
||||
if op.Parallelism != defaultParallelism {
|
||||
return nil, fmt.Errorf(strings.TrimSpace(planErrParallelismNotSupported))
|
||||
}
|
||||
|
||||
if op.Plan != nil {
|
||||
return nil, fmt.Errorf(strings.TrimSpace(planErrPlanNotSupported))
|
||||
}
|
||||
|
@ -38,10 +46,19 @@ func (b *Remote) opPlan(stopCtx, cancelCtx context.Context, op *backend.Operatio
|
|||
return nil, fmt.Errorf(strings.TrimSpace(planErrOutPathNotSupported))
|
||||
}
|
||||
|
||||
if !op.PlanRefresh {
|
||||
return nil, fmt.Errorf(strings.TrimSpace(planErrNoRefreshNotSupported))
|
||||
}
|
||||
|
||||
if op.Targets != nil {
|
||||
return nil, fmt.Errorf(strings.TrimSpace(planErrTargetsNotSupported))
|
||||
}
|
||||
|
||||
if op.Variables != nil {
|
||||
return nil, fmt.Errorf(strings.TrimSpace(
|
||||
fmt.Sprintf(planErrVariablesNotSupported, b.hostname, b.organization, op.Workspace)))
|
||||
}
|
||||
|
||||
if (op.Module == nil || op.Module.Config().Dir == "") && !op.Destroy {
|
||||
return nil, fmt.Errorf(strings.TrimSpace(planErrNoConfig))
|
||||
}
|
||||
|
@ -203,11 +220,25 @@ Insufficient rights to generate a plan!
|
|||
to generate plans, at least plan permissions on the workspace are required.[reset]
|
||||
`
|
||||
|
||||
const planErrModuleDepthNotSupported = `
|
||||
Custom module depths are currently not supported!
|
||||
|
||||
The "remote" backend does not support setting a custom module
|
||||
depth at this time.
|
||||
`
|
||||
|
||||
const planErrParallelismNotSupported = `
|
||||
Custom parallelism values are currently not supported!
|
||||
|
||||
The "remote" backend does not support setting a custom parallelism
|
||||
value at this time.
|
||||
`
|
||||
|
||||
const planErrPlanNotSupported = `
|
||||
Displaying a saved plan is currently not supported!
|
||||
|
||||
The "remote" backend currently requires configuration to be present
|
||||
and does not accept an existing saved plan as an argument at this time.
|
||||
The "remote" backend currently requires configuration to be present and
|
||||
does not accept an existing saved plan as an argument at this time.
|
||||
`
|
||||
|
||||
const planErrOutPathNotSupported = `
|
||||
|
@ -217,12 +248,32 @@ The "remote" backend does not support saving the generated execution
|
|||
plan locally at this time.
|
||||
`
|
||||
|
||||
const planErrNoRefreshNotSupported = `
|
||||
Planning without refresh is currently not supported!
|
||||
|
||||
Currently the "remote" backend will always do an in-memory refresh of
|
||||
the Terraform state prior to generating the plan.
|
||||
`
|
||||
|
||||
const planErrTargetsNotSupported = `
|
||||
Resource targeting is currently not supported!
|
||||
|
||||
The "remote" backend does not support resource targeting at this time.
|
||||
`
|
||||
|
||||
const planErrVariablesNotSupported = `
|
||||
Run variables are currently not supported!
|
||||
|
||||
The "remote" backend does not support setting run variables at this time.
|
||||
Currently the only to way to pass variables to the remote backend is by
|
||||
creating a '*.auto.tfvars' variables file. This file will automatically
|
||||
be loaded by the "remote" backend when the workspace is configured to use
|
||||
Terraform v0.10.0 or later.
|
||||
|
||||
Additionally you can also set variables on the workspace in the web UI:
|
||||
https://%s/app/%s/%s/variables
|
||||
`
|
||||
|
||||
const planErrNoConfig = `
|
||||
No configuration files found!
|
||||
|
||||
|
|
|
@ -18,7 +18,10 @@ import (
|
|||
|
||||
func testOperationPlan() *backend.Operation {
|
||||
return &backend.Operation{
|
||||
Type: backend.OperationTypePlan,
|
||||
ModuleDepth: defaultModuleDepth,
|
||||
Parallelism: defaultParallelism,
|
||||
PlanRefresh: true,
|
||||
Type: backend.OperationTypePlan,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,6 +88,56 @@ func TestRemote_planWithoutPermissions(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRemote_planWithModuleDepth(t *testing.T) {
|
||||
b := testBackendDefault(t)
|
||||
|
||||
mod, modCleanup := module.TestTree(t, "./test-fixtures/plan")
|
||||
defer modCleanup()
|
||||
|
||||
op := testOperationPlan()
|
||||
op.Module = mod
|
||||
op.ModuleDepth = 1
|
||||
op.Workspace = backend.DefaultStateName
|
||||
|
||||
run, err := b.Operation(context.Background(), op)
|
||||
if err != nil {
|
||||
t.Fatalf("error starting operation: %v", err)
|
||||
}
|
||||
<-run.Done()
|
||||
|
||||
if run.Err == nil {
|
||||
t.Fatalf("expected a plan error, got: %v", run.Err)
|
||||
}
|
||||
if !strings.Contains(run.Err.Error(), "module depths are currently not supported") {
|
||||
t.Fatalf("expected a module depth error, got: %v", run.Err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemote_planWithParallelism(t *testing.T) {
|
||||
b := testBackendDefault(t)
|
||||
|
||||
mod, modCleanup := module.TestTree(t, "./test-fixtures/plan")
|
||||
defer modCleanup()
|
||||
|
||||
op := testOperationPlan()
|
||||
op.Module = mod
|
||||
op.Parallelism = 3
|
||||
op.Workspace = backend.DefaultStateName
|
||||
|
||||
run, err := b.Operation(context.Background(), op)
|
||||
if err != nil {
|
||||
t.Fatalf("error starting operation: %v", err)
|
||||
}
|
||||
<-run.Done()
|
||||
|
||||
if run.Err == nil {
|
||||
t.Fatalf("expected a plan error, got: %v", run.Err)
|
||||
}
|
||||
if !strings.Contains(run.Err.Error(), "parallelism values are currently not supported") {
|
||||
t.Fatalf("expected a parallelism error, got: %v", run.Err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemote_planWithPlan(t *testing.T) {
|
||||
b := testBackendDefault(t)
|
||||
|
||||
|
@ -135,6 +188,31 @@ func TestRemote_planWithPath(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRemote_planWithoutRefresh(t *testing.T) {
|
||||
b := testBackendDefault(t)
|
||||
|
||||
mod, modCleanup := module.TestTree(t, "./test-fixtures/plan")
|
||||
defer modCleanup()
|
||||
|
||||
op := testOperationPlan()
|
||||
op.Module = mod
|
||||
op.PlanRefresh = false
|
||||
op.Workspace = backend.DefaultStateName
|
||||
|
||||
run, err := b.Operation(context.Background(), op)
|
||||
if err != nil {
|
||||
t.Fatalf("error starting operation: %v", err)
|
||||
}
|
||||
<-run.Done()
|
||||
|
||||
if run.Err == nil {
|
||||
t.Fatalf("expected a plan error, got: %v", run.Err)
|
||||
}
|
||||
if !strings.Contains(run.Err.Error(), "refresh is currently not supported") {
|
||||
t.Fatalf("expected a refresh error, got: %v", run.Err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemote_planWithTarget(t *testing.T) {
|
||||
b := testBackendDefault(t)
|
||||
|
||||
|
@ -160,6 +238,31 @@ func TestRemote_planWithTarget(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRemote_planWithVariables(t *testing.T) {
|
||||
b := testBackendDefault(t)
|
||||
|
||||
mod, modCleanup := module.TestTree(t, "./test-fixtures/plan")
|
||||
defer modCleanup()
|
||||
|
||||
op := testOperationPlan()
|
||||
op.Module = mod
|
||||
op.Variables = map[string]interface{}{"foo": "bar"}
|
||||
op.Workspace = backend.DefaultStateName
|
||||
|
||||
run, err := b.Operation(context.Background(), op)
|
||||
if err != nil {
|
||||
t.Fatalf("error starting operation: %v", err)
|
||||
}
|
||||
<-run.Done()
|
||||
|
||||
if run.Err == nil {
|
||||
t.Fatalf("expected an plan error, got: %v", run.Err)
|
||||
}
|
||||
if !strings.Contains(run.Err.Error(), "variables are currently not supported") {
|
||||
t.Fatalf("expected a variables error, got: %v", run.Err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemote_planNoConfig(t *testing.T) {
|
||||
b := testBackendDefault(t)
|
||||
|
||||
|
|
|
@ -147,13 +147,13 @@ func (c *ApplyCommand) Run(args []string) int {
|
|||
|
||||
// Build the operation
|
||||
opReq := c.Operation()
|
||||
opReq.AutoApprove = autoApprove
|
||||
opReq.Destroy = c.Destroy
|
||||
opReq.DestroyForce = destroyForce
|
||||
opReq.Module = mod
|
||||
opReq.Plan = plan
|
||||
opReq.PlanRefresh = refresh
|
||||
opReq.Type = backend.OperationTypeApply
|
||||
opReq.AutoApprove = autoApprove
|
||||
opReq.DestroyForce = destroyForce
|
||||
|
||||
op, err := c.RunOperation(b, opReq)
|
||||
if err != nil {
|
||||
|
|
|
@ -167,9 +167,11 @@ func (m *Meta) IsLocalBackend(b backend.Backend) bool {
|
|||
func (m *Meta) Operation() *backend.Operation {
|
||||
return &backend.Operation{
|
||||
PlanOutBackend: m.backendState,
|
||||
Parallelism: m.parallelism,
|
||||
Targets: m.targets,
|
||||
UIIn: m.UIInput(),
|
||||
UIOut: m.Ui,
|
||||
Variables: m.variables,
|
||||
Workspace: m.Workspace(),
|
||||
LockState: m.stateLock,
|
||||
StateLockTimeout: m.stateLockTimeout,
|
||||
|
|
|
@ -100,9 +100,10 @@ func (c *PlanCommand) Run(args []string) int {
|
|||
opReq := c.Operation()
|
||||
opReq.Destroy = destroy
|
||||
opReq.Module = mod
|
||||
opReq.ModuleDepth = moduleDepth
|
||||
opReq.Plan = plan
|
||||
opReq.PlanRefresh = refresh
|
||||
opReq.PlanOutPath = outPath
|
||||
opReq.PlanRefresh = refresh
|
||||
opReq.Type = backend.OperationTypePlan
|
||||
|
||||
// Perform the operation
|
||||
|
|
Loading…
Reference in New Issue