diff --git a/DOCS.md b/DOCS.md index c6d2870..8f0ed90 100644 --- a/DOCS.md +++ b/DOCS.md @@ -124,6 +124,49 @@ pipeline: root_dir: some/path/here ``` +## Targets +You may want to only target a specific list of resources within your terraform code. To achieve this you can specify the `targets` parameter. If left undefined all resources will be planned/applied against as the default behavior. + +Single target: + +```yaml +pipeline: + terraform: + image: jmccann/drone-terraform:0.5 + plan: false + targets: aws_security_group.generic_sg + remote: + backend: S3 + config: + bucket: my-terraform-config-bucket + key: tf-states/my-project + region: us-east-1 + vars: + app_name: my-project + app_version: 1.0.0 +``` + +Multiple targets: + +```yaml +pipeline: + terraform: + image: jmccann/drone-terraform:0.5 + plan: false + targets: + - aws_security_group.generic_sg + - aws_security_group.app_sg + remote: + backend: S3 + config: + bucket: my-terraform-config-bucket + key: tf-states/my-project + region: us-east-1 + vars: + app_name: my-project + app_version: 1.0.0 +``` + ## Parallelism You may want to limit the number of concurrent operations as Terraform walks its graph. If you want to change Terraform's default parallelism (currently equal to 10) then set the `parallelism` parameter. diff --git a/main.go b/main.go index 49c4586..d80a411 100644 --- a/main.go +++ b/main.go @@ -4,8 +4,8 @@ import ( "encoding/json" "os" - "github.com/joho/godotenv" "github.com/Sirupsen/logrus" + "github.com/joho/godotenv" "github.com/urfave/cli" ) @@ -24,55 +24,61 @@ func main() { // cli.BoolFlag{ - Name: "plan", - Usage: "calculates a plan but does NOT apply it", + Name: "plan", + Usage: "calculates a plan but does NOT apply it", EnvVar: "PLUGIN_PLAN", }, cli.StringFlag{ - Name: "remote", - Usage: "contains the configuration for the Terraform remote state tracking", + Name: "remote", + Usage: "contains the configuration for the Terraform remote state tracking", EnvVar: "PLUGIN_REMOTE", }, cli.StringFlag{ - Name: "vars", - Usage: "a map of variables to pass to the Terraform `plan` and `apply` commands. Each value is passed as a `=` option", + Name: "vars", + Usage: "a map of variables to pass to the Terraform `plan` and `apply` commands. Each value is passed as a `=` option", EnvVar: "PLUGIN_VARS", }, cli.StringFlag{ - Name: "secrets", - Usage: "a map of secrets to pass to the Terraform `plan` and `apply` commands. Each value is passed as a `=` option", + Name: "secrets", + Usage: "a map of secrets to pass to the Terraform `plan` and `apply` commands. Each value is passed as a `=` option", EnvVar: "PLUGIN_SECRETS", }, cli.StringFlag{ - Name: "ca_cert", - Usage: "ca cert to add to your environment to allow terraform to use internal/private resources", + Name: "ca_cert", + Usage: "ca cert to add to your environment to allow terraform to use internal/private resources", EnvVar: "PLUGIN_CA_CERT", }, cli.BoolFlag{ - Name: "sensitive", - Usage: "whether or not to suppress terraform commands to stdout", + Name: "sensitive", + Usage: "whether or not to suppress terraform commands to stdout", EnvVar: "PLUGIN_SENSITIVE", }, cli.StringFlag{ - Name: "role_arn_to_assume", - Usage: "A role to assume before running the terraform commands", + Name: "role_arn_to_assume", + Usage: "A role to assume before running the terraform commands", EnvVar: "PLUGIN_ROLE_ARN_TO_ASSUME", }, cli.StringFlag{ - Name: "root_dir", - Usage: "The root directory where the terraform files live. When unset, the top level directory will be assumed", + Name: "root_dir", + Usage: "The root directory where the terraform files live. When unset, the top level directory will be assumed", EnvVar: "PLUGIN_ROOT_DIR", }, cli.IntFlag{ - Name: "parallelism", - Usage: "The number of concurrent operations as Terraform walks its graph", + Name: "parallelism", + Usage: "The number of concurrent operations as Terraform walks its graph", EnvVar: "PLUGIN_PARALLELISM", }, cli.StringFlag{ - Name: "env-file", + Name: "env-file", Usage: "source env file", }, + + cli.StringSliceFlag{ + Name: "targets", + Usage: "targets to run apply or plan on", + EnvVar: "PLUGIN_TARGETS", + }, } if err := app.Run(os.Args); err != nil { @@ -116,6 +122,7 @@ func run(c *cli.Context) error { RoleARN: c.String("role_arn_to_assume"), RootDir: c.String("root_dir"), Parallelism: c.Int("parallelism"), + Targets: c.StringSlice("targets"), }, } diff --git a/plugin.go b/plugin.go index 7a8adba..818b291 100644 --- a/plugin.go +++ b/plugin.go @@ -2,11 +2,11 @@ package main import ( "fmt" + "github.com/Sirupsen/logrus" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials/stscreds" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/sts" - "github.com/Sirupsen/logrus" "io/ioutil" "os" "os/exec" @@ -25,6 +25,7 @@ type ( RoleARN string RootDir string Parallelism int + Targets []string } Remote struct { @@ -52,9 +53,9 @@ func (p Plugin) Exec() error { commands = append(commands, remoteConfigCommand(remote)) } commands = append(commands, getModules()) - commands = append(commands, planCommand(p.Config.Vars, p.Config.Secrets, p.Config.Parallelism)) + commands = append(commands, planCommand(p.Config.Vars, p.Config.Secrets, p.Config.Parallelism, p.Config.Targets)) if !p.Config.Plan { - commands = append(commands, applyCommand(p.Config.Parallelism)) + commands = append(commands, applyCommand(p.Config.Parallelism, p.Config.Targets)) } commands = append(commands, deleteCache()) @@ -123,11 +124,14 @@ func getModules() *exec.Cmd { ) } -func planCommand(variables map[string]string, secrets map[string]string, parallelism int) *exec.Cmd { +func planCommand(variables map[string]string, secrets map[string]string, parallelism int, targets []string) *exec.Cmd { args := []string{ "plan", "-out=plan.tfout", } + for _, v := range targets { + args = append(args, "--target", fmt.Sprintf("%s", v)) + } for k, v := range variables { args = append(args, "-var") args = append(args, fmt.Sprintf("%s=%s", k, v)) @@ -145,10 +149,13 @@ func planCommand(variables map[string]string, secrets map[string]string, paralle ) } -func applyCommand(parallelism int) *exec.Cmd { +func applyCommand(parallelism int, targets []string) *exec.Cmd { args := []string{ "apply", } + for _, v := range targets { + args = append(args, "--target", fmt.Sprintf("%s", v)) + } if parallelism > 0 { args = append(args, fmt.Sprintf("-parallelism=%d", parallelism)) }