Skip to content

Instantly share code, notes, and snippets.

@justinholmes
Created February 28, 2018 16:36
Show Gist options
  • Save justinholmes/af62356ebd485e4b63e1e3153baef392 to your computer and use it in GitHub Desktop.
Save justinholmes/af62356ebd485e4b63e1e3153baef392 to your computer and use it in GitHub Desktop.
Cloudbuild trigger provider
package google
import (
"fmt"
"github.com/hashicorp/terraform/helper/schema"
"google.golang.org/api/cloudbuild/v1"
"log"
"strings"
)
func resourceCloudbuildTrigger() *schema.Resource {
return &schema.Resource{
Create: resourceCloudbuildTriggerCreate,
Read: resourceCloudbuildTriggerRead,
Delete: resourceCloudbuildTriggerDelete,
Update: resourceCloudbuildTriggerUpdate,
Schema: map[string]*schema.Schema{
"project": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"description": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"filename": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"substitutions": &schema.Schema{
Type: schema.TypeMap,
Optional: true,
Elem: schema.TypeString,
},
"disabled": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
},
"trigger_template": &schema.Schema{
Optional: true,
Type: schema.TypeList,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"branch_name": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"commit_sha": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"dir": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"project_id": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"repo_name": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"tag_name": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
},
},
},
"build": &schema.Schema{
Optional: true,
Type: schema.TypeList,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"images": &schema.Schema{
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"logs_bucket": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"options": &schema.Schema{
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"disk_size_gb": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
},
"log_streaming_option": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"machine_type": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"requested_verify_option": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"source_provenance_hash": &schema.Schema{
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"substitution_option": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
},
},
},
"secrets": &schema.Schema{
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"kms_key_name": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"secret_env": &schema.Schema{
Type: schema.TypeMap,
Optional: true,
Elem: schema.TypeString,
},
},
},
},
"substitutions": &schema.Schema{
Type: schema.TypeMap,
Optional: true,
Elem: schema.TypeString,
},
"tags": &schema.Schema{
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"timeout": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"steps": &schema.Schema{
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"args": &schema.Schema{
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"dir": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"entrypoint": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"env": &schema.Schema{
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"id": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"name": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"secret_env": &schema.Schema{
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"volumes": &schema.Schema{
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"path": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
},
},
},
"wait_for": &schema.Schema{
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
},
},
},
},
},
},
}
}
func resourceCloudbuildTriggerCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
project, err := getProject(d, config)
if err != nil {
return err
}
buildTrigger := addOptionalFields(d)
trigger, err := config.clientCloudbuild.Projects.Triggers.Create(project, buildTrigger).Do()
if err != nil {
return fmt.Errorf("Error creating Cloudbuild Trigger: %s", err)
}
log.Printf("[INFO] Cloudbuild Trigger %s has been created", trigger.Id)
d.SetId(trigger.Id)
return resourceCloudbuildTriggerRead(d, meta)
}
func resourceCloudbuildTriggerRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
project, err := getProject(d, config)
if err != nil {
return err
}
Id := d.Id()
_, err = config.clientCloudbuild.Projects.Triggers.Get(project, Id).Do()
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("Cloudbuild Trigger %q", Id))
}
return nil
}
func addOptionalFields(d *schema.ResourceData) *cloudbuild.BuildTrigger {
buildTrigger := &cloudbuild.BuildTrigger{}
if v, ok := d.GetOk("description"); ok {
buildTrigger.Description = v.(string)
}
if v, ok := d.GetOk("filename"); ok {
buildTrigger.Filename = v.(string)
}
if v, ok := d.GetOk("disabled"); ok {
buildTrigger.Disabled = v.(bool)
}
if v, ok := d.Get("substitutions").(map[string]string); ok {
if (len(v)) > 0 {
buildTrigger.Substitutions = v
}
}
buildTrigger.TriggerTemplate = addTriggerTemplate(d)
buildTrigger.Build = addBuildTemplate(d)
return buildTrigger
}
func addTriggerTemplate(d *schema.ResourceData) *cloudbuild.RepoSource {
repoSource := &cloudbuild.RepoSource{}
if _triggerTemplate, ok := d.GetOk("trigger_template"); ok {
triggerTemplate := _triggerTemplate.([]interface{})[0].(map[string]interface{})
if v, ok := triggerTemplate["branch_name"]; ok {
repoSource.BranchName = v.(string)
}
if v, ok := triggerTemplate["commit_sha"]; ok {
repoSource.CommitSha = v.(string)
}
if v, ok := triggerTemplate["dir"]; ok {
repoSource.Dir = v.(string)
}
if v, ok := triggerTemplate["project_id"]; ok {
repoSource.ProjectId = v.(string)
}
if v, ok := triggerTemplate["repo_name"]; ok {
repoSource.RepoName = v.(string)
}
if v, ok := triggerTemplate["tag_name"]; ok {
repoSource.TagName = v.(string)
}
}
return repoSource
}
func addBuildTemplate(d *schema.ResourceData) *cloudbuild.Build {
build := &cloudbuild.Build{}
if _buildSchema, ok := d.GetOk("build"); ok {
buildSchema := _buildSchema.([]interface{})[0].(map[string]interface{})
if v, ok := buildSchema["logs_bucket"]; ok {
build.LogsBucket = v.(string)
}
build.Images = convertStringArr(buildSchema["images"].([]interface{}))
build.Tags = convertStringArr(buildSchema["tags"].([]interface{}))
var targetSubstitutions map[string]string
if v := buildSchema["substitutions"].(map[string]interface{}); len(v) > 0 {
targetSubstitutions = make(map[string]string, len(v))
for k, v := range v {
targetSubstitutions[k] = v.(string)
}
}
build.Substitutions = targetSubstitutions
if v, ok := buildSchema["timeout"]; ok {
build.Timeout = v.(string)
}
if _secretsTemplate, ok := buildSchema["secrets"]; ok {
build.Secrets = addSecretsTemplate(_secretsTemplate)
}
if _optionsTemplate, ok := buildSchema["options"]; ok {
opts := _optionsTemplate.([]interface{})
if len(opts) > 0 {
build.Options = addOptionsTemplate(opts)
}
}
if _stepsTemplate, ok := buildSchema["steps"]; ok {
build.Steps = addBuildStepsTemplate(_stepsTemplate)
}
if v, ok := buildSchema["timeout"].(string); ok {
if (len(v)) > 0 {
build.Timeout = v
}
}
}
return build
}
func addSecretsTemplate(_secretsTemplate interface{}) []*cloudbuild.Secret {
secretList := []*cloudbuild.Secret{}
_secrets := _secretsTemplate.([]interface{})
for _, _secretTemplate := range _secrets {
var kmsKeyName string
secretTemplate := _secretTemplate.(map[string]interface{})
if v, ok := secretTemplate["kms_key_name"]; ok {
kmsKeyName = v.(string)
}
secretEnvMap := make(map[string]string)
if v, ok := secretTemplate["secret_env"].(map[string]string); ok {
if (len(v)) > 0 {
secretEnvMap = v
}
}
if len(strings.TrimSpace(kmsKeyName)) != 0 {
secret := new(cloudbuild.Secret)
secret.KmsKeyName = kmsKeyName
secret.SecretEnv = secretEnvMap
secretList = append(secretList, secret)
}
}
return secretList
}
func addOptionsTemplate(_optionsTemplate []interface{}) *cloudbuild.BuildOptions {
buildOptions := new(cloudbuild.BuildOptions)
options := _optionsTemplate[0].(map[string]interface{})
if v, ok := options["disk_size_gb"]; ok {
buildOptions.DiskSizeGb = int64(v.(int))
}
if v, ok := options["log_streaming_option"]; ok {
buildOptions.LogStreamingOption = v.(string)
}
if v, ok := options["machine_type"]; ok {
buildOptions.MachineType = v.(string)
}
if v, ok := options["requested_verify_option"]; ok {
buildOptions.RequestedVerifyOption = v.(string)
}
var targetSourceProvenanceHash []string
if v := options["source_provenance_hash"].([]string); len(v) > 0 {
for i, v := range v {
targetSourceProvenanceHash[i] = v
}
}
buildOptions.SourceProvenanceHash = targetSourceProvenanceHash
if v, ok := options["substitution_option"]; ok {
buildOptions.SubstitutionOption = v.(string)
}
return buildOptions
}
func addBuildStepsTemplate(_stepsTemplate interface{}) []*cloudbuild.BuildStep {
stepList := []*cloudbuild.BuildStep{}
_steps := _stepsTemplate.([]interface{})
for _, _stepTemplate := range _steps {
stepTemplate := _stepTemplate.(map[string]interface{})
buildStep := new(cloudbuild.BuildStep)
buildStep.Args = convertStringArr(stepTemplate["args"].([]interface{}))
if v, ok := stepTemplate["dir"]; ok {
buildStep.Dir = v.(string)
}
if v, ok := stepTemplate["entrypoint"]; ok {
buildStep.Entrypoint = v.(string)
}
buildStep.Env = convertStringArr(stepTemplate["env"].([]interface{}))
if v, ok := stepTemplate["id"]; ok {
buildStep.Id = v.(string)
}
if v, ok := stepTemplate["name"]; ok {
buildStep.Name = v.(string)
}
buildStep.SecretEnv = convertStringArr(stepTemplate["secret_env"].([]interface{}))
if _volumesTemplate, ok := stepTemplate["volumes"]; ok {
buildStep.Volumes = addVolumesTemplate(_volumesTemplate)
}
buildStep.WaitFor = convertStringArr(stepTemplate["wait_for"].([]interface{}))
stepList = append(stepList, buildStep)
}
return stepList
}
func addVolumesTemplate(_volumesTemplate interface{}) []*cloudbuild.Volume {
volumeList := []*cloudbuild.Volume{}
_volumes := _volumesTemplate.([]interface{})
for _, _volumeTemplate := range _volumes {
volumeTemplate := _volumeTemplate.(map[string]interface{})
volume := new(cloudbuild.Volume)
if v, ok := volumeTemplate["name"]; ok {
volume.Name = v.(string)
}
if v, ok := volumeTemplate["path"]; ok {
volume.Path = v.(string)
}
volumeList = append(volumeList, volume)
}
return volumeList
}
func resourceCloudbuildTriggerDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
project, err := getProject(d, config)
if err != nil {
return err
}
_, err = config.clientCloudbuild.Projects.Triggers.Delete(project, d.Id()).Do()
if err != nil {
return fmt.Errorf("Error deleting Cloudbuild Trigger: %s", err)
}
d.SetId("")
return err
}
func resourceCloudbuildTriggerUpdate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
project, err := getProject(d, config)
if err != nil {
return err
}
buildTrigger := addOptionalFields(d)
_, err = config.clientCloudbuild.Projects.Triggers.Patch(project, d.Id(), buildTrigger).Do()
if err != nil {
return fmt.Errorf("Error updating Cloudbuild Trigger: %s", err)
}
return resourceCloudbuildTriggerRead(d, meta)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment