├── main.go ├── .gitignore ├── scripts ├── gofmtcheck.sh ├── build.sh └── build-ci.sh ├── infoblox ├── config.go ├── provider_test.go ├── provider.go ├── helpers.go ├── resource_infoblox_record_txt.go ├── resource_infoblox_record_cname.go ├── resource_infoblox_record_aaaa.go ├── resource_infoblox_record_mx.go ├── resource_infoblox_record_a.go ├── resource_infoblox_record_srv.go ├── resource_infoblox_ip.go ├── resource_infoblox_record_ptr.go ├── resource_infoblox_record.go ├── resource_infoblox_record_host.go └── resource_infoblox_record_test.go ├── .travis.yml ├── Makefile ├── README.md ├── LICENSE └── vendor └── vendor.json /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform/plugin" 5 | 6 | "github.com/prudhvitella/terraform-provider-infoblox/infoblox" 7 | ) 8 | 9 | func main() { 10 | plugin.Serve(&plugin.ServeOpts{ 11 | ProviderFunc: infoblox.Provider, 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.dll 2 | *.exe 3 | .DS_Store 4 | example.tf 5 | terraform.tfplan 6 | terraform.tfstate 7 | bin/ 8 | modules-dev/ 9 | pkg/ 10 | vendor/*/ 11 | website/.vagrant 12 | website/build 13 | website/node_modules 14 | .vagrant/ 15 | *.backup 16 | ./*.tfstate 17 | .terraform/ 18 | *.log 19 | *.bak 20 | *~ 21 | .*.swp 22 | .idea 23 | -------------------------------------------------------------------------------- /scripts/gofmtcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Check gofmt 4 | echo "==> Checking that code complies with gofmt requirements..." 5 | gofmt_files=$(gofmt -l `find . -name '*.go' | grep -v vendor`) 6 | if [[ -n ${gofmt_files} ]]; then 7 | echo 'gofmt needs running on the following files:' 8 | echo "${gofmt_files}" 9 | echo "You can use the command: \`make fmt\` to reformat code." 10 | exit 1 11 | fi 12 | 13 | exit 0 14 | -------------------------------------------------------------------------------- /infoblox/config.go: -------------------------------------------------------------------------------- 1 | package infoblox 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/fanatic/go-infoblox" 7 | ) 8 | 9 | // Config holds authentication details of Infoblox 10 | type Config struct { 11 | Host string 12 | Password string 13 | Username string 14 | SSLVerify bool 15 | UseCookies bool 16 | } 17 | 18 | // Client returns a new client for accessing Infoblox. 19 | func (c *Config) Client() (*infoblox.Client, error) { 20 | client := infoblox.NewClient(c.Host, c.Username, c.Password, c.SSLVerify, c.UseCookies) 21 | 22 | log.Printf("[INFO] Infoblox Client configured for user: %s", client.Username) 23 | 24 | return client, nil 25 | } 26 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.9 4 | install: 5 | - echo noop 6 | script: 7 | - go get -u golang.org/x/lint/golint 8 | - golint ./... 9 | - make test 10 | before_install: 11 | - go get github.com/mitchellh/gox 12 | - go get github.com/tcnksm/ghr 13 | - go get github.com/davecgh/go-spew/spew 14 | - go get github.com/hashicorp/logutils 15 | - go get -u github.com/fanatic/go-infoblox 16 | - go get -u github.com/kardianos/govendor 17 | - govendor sync 18 | after_success: 19 | - make ci 20 | - ghr --username prudhvitella --token $GITHUB_TOKEN --delete --prerelease --debug pre-release dist/ 21 | branches: 22 | only: 23 | - master 24 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | XC_OS=$(go env GOOS) 4 | XC_ARCH=$(go env GOARCH) 5 | DEST_BIN=terraform-provider-infoblox 6 | 7 | echo "Compiling for OS: $XC_OS and ARCH: $XC_ARCH" 8 | 9 | gox -os="${XC_OS}" -arch="${XC_ARCH}" 10 | 11 | if [ $? != 0 ] ; then 12 | echo "Failed to compile, bailing." 13 | exit 1 14 | fi 15 | 16 | echo "Looking for Terraform install" 17 | 18 | TERRAFORM=$(which terraform) 19 | 20 | [ $TERRAFORM ] && TERRAFORM_LOC=$(dirname ${TERRAFORM}) 21 | 22 | if [ $TERRAFORM_LOC ] ; then 23 | DEST_PATH=$TERRAFORM_LOC 24 | else 25 | DEST_PATH=$GOPATH/bin 26 | fi 27 | 28 | echo "" 29 | echo "Moving terraform-provider-infoblox_${XC_OS}_${XC_ARCH} to $DEST_PATH/$DEST_BIN" 30 | echo "" 31 | 32 | mv terraform-provider-infoblox_${XC_OS}_${XC_ARCH} $DEST_PATH/$DEST_BIN 33 | 34 | echo "Resulting binary: " 35 | echo "" 36 | echo $(ls -la $DEST_PATH/$DEST_BIN) 37 | -------------------------------------------------------------------------------- /scripts/build-ci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This script builds the application from source for multiple platforms. 4 | 5 | # Get the parent directory of where this script is. 6 | 7 | SOURCE="${BASH_SOURCE[0]}" 8 | while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done 9 | DIR="$( cd -P "$( dirname "$SOURCE" )/.." && pwd )" 10 | 11 | # Change into that directory 12 | cd "$DIR" 13 | 14 | # Determine the arch/os combos we're building for 15 | XC_ARCH=${XC_ARCH:-"386 amd64 arm"} 16 | XC_OS=${XC_OS:-linux darwin windows} 17 | 18 | gox \ 19 | -os="${XC_OS}" \ 20 | -arch="${XC_ARCH}" \ 21 | -output "dist/{{.OS}}_{{.Arch}}_{{.Dir}}" \ 22 | ./... 23 | 24 | # Done! 25 | echo 26 | echo "==> Results:" 27 | ls -hl dist/* 28 | 29 | echo "==> Generating checksums:" 30 | if command -v sha256sum >/dev/null 2>&1 ; then 31 | sha256sum dist/* 32 | elif command -v shasum >/dev/null 2>&1 ; then 33 | shasum -a 256 dist/* 34 | else 35 | echo "Neither sha256sum nor shasum available, abandoned checksum generation" 36 | fi 37 | 38 | -------------------------------------------------------------------------------- /infoblox/provider_test.go: -------------------------------------------------------------------------------- 1 | package infoblox 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/hashicorp/terraform/helper/schema" 8 | "github.com/hashicorp/terraform/terraform" 9 | ) 10 | 11 | var testAccProviders map[string]terraform.ResourceProvider 12 | var testAccProvider *schema.Provider 13 | 14 | func init() { 15 | testAccProvider = Provider().(*schema.Provider) 16 | testAccProviders = map[string]terraform.ResourceProvider{ 17 | "infoblox": testAccProvider, 18 | } 19 | } 20 | 21 | func TestProvider(t *testing.T) { 22 | if err := Provider().(*schema.Provider).InternalValidate(); err != nil { 23 | t.Fatalf("err: %s", err) 24 | } 25 | } 26 | 27 | func TestProvider_impl(t *testing.T) { 28 | var _ terraform.ResourceProvider = Provider() 29 | } 30 | 31 | func testAccPreCheck(t *testing.T) { 32 | if v := os.Getenv("INFOBLOX_USERNAME"); v == "" { 33 | t.Fatal("INFOBLOX_USERNAME must be set for acceptance tests") 34 | } 35 | 36 | if v := os.Getenv("INFOBLOX_PASSWORD"); v == "" { 37 | t.Fatal("INFOBLOX_PASSWORD must be set for acceptance tests") 38 | } 39 | 40 | if v := os.Getenv("INFOBLOX_HOST"); v == "" { 41 | t.Fatal("INFOBLOX_HOST must be set for acceptance tests.") 42 | } 43 | 44 | if v := os.Getenv("INFOBLOX_SSLVERIFY"); v == "" { 45 | t.Fatal("INFOBLOX_SSLVERIFY must be set for acceptance tests") 46 | } 47 | 48 | if v := os.Getenv("INFOBLOX_USECOOKIES"); v == "" { 49 | t.Fatal("INFOBLOX_USECOOKIES must be set for acceptance tests") 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TEST?=$$(go list ./... | grep -v /vendor/) 2 | VETARGS?=-asmdecl -atomic -bool -buildtags -copylocks -methods -nilfunc -printf -rangeloops -shift -structtags -unsafeptr 3 | 4 | default: test 5 | 6 | bin: fmtcheck generate 7 | @sh -c "'$(CURDIR)/scripts/build.sh'" 8 | 9 | ci: fmtcheck generate 10 | @sh -c "'$(CURDIR)/scripts/build-ci.sh'" 11 | 12 | # test runs the unit tests and vets the code 13 | test: fmtcheck generate 14 | TF_ACC= go test $(TEST) $(TESTARGS) -timeout=30s -parallel=4 15 | 16 | # testacc runs acceptance tests 17 | testacc: fmtcheck generate 18 | TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout 90m 19 | 20 | # testrace runs the race checker 21 | testrace: fmtcheck generate 22 | TF_ACC= go test -race $(TEST) $(TESTARGS) 23 | 24 | cover: 25 | @go tool cover 2>/dev/null; if [ $$? -eq 3 ]; then \ 26 | go get -u golang.org/x/tools/cmd/cover; \ 27 | fi 28 | go test $(TEST) -coverprofile=coverage.out 29 | go tool cover -html=coverage.out 30 | rm coverage.out 31 | 32 | # vet runs the Go source code static analysis tool `vet` to find 33 | # any common errors. 34 | vet: 35 | @go tool vet 2>/dev/null ; if [ $$? -eq 3 ]; then \ 36 | go get golang.org/x/tools/cmd/vet; \ 37 | fi 38 | @echo "go tool vet $(VETARGS) $(TEST) " 39 | @go tool vet $(VETARGS) $(TEST) ; if [ $$? -eq 1 ]; then \ 40 | echo ""; \ 41 | echo "Vet found suspicious constructs. Please check the reported constructs"; \ 42 | echo "and fix them if necessary before submitting the code for review."; \ 43 | exit 1; \ 44 | fi 45 | 46 | # generate runs `go generate` to build the dynamically generated 47 | # source files. 48 | generate: 49 | go generate $$(go list ./... | grep -v /vendor/) 50 | 51 | fmt: 52 | gofmt -w . 53 | 54 | fmtcheck: 55 | @sh -c "'$(CURDIR)/scripts/gofmtcheck.sh'" 56 | 57 | .PHONY: bin default generate test updatedeps vet fmt fmtcheck 58 | -------------------------------------------------------------------------------- /infoblox/provider.go: -------------------------------------------------------------------------------- 1 | package infoblox 2 | 3 | import ( 4 | "github.com/hashicorp/terraform/helper/schema" 5 | "github.com/hashicorp/terraform/terraform" 6 | ) 7 | 8 | //Provider returns a terraform.ResourceProvider. 9 | func Provider() terraform.ResourceProvider { 10 | return &schema.Provider{ 11 | Schema: map[string]*schema.Schema{ 12 | "username": &schema.Schema{ 13 | Type: schema.TypeString, 14 | Required: true, 15 | DefaultFunc: schema.EnvDefaultFunc("INFOBLOX_USERNAME", nil), 16 | Description: "Infoblox Username", 17 | }, 18 | "password": &schema.Schema{ 19 | Type: schema.TypeString, 20 | Required: true, 21 | DefaultFunc: schema.EnvDefaultFunc("INFOBLOX_PASSWORD", nil), 22 | Description: "Infoblox User Password", 23 | }, 24 | "host": &schema.Schema{ 25 | Type: schema.TypeString, 26 | Required: true, 27 | DefaultFunc: schema.EnvDefaultFunc("INFOBLOX_HOST", nil), 28 | Description: "Infoblox Base Url(defaults to testing)", 29 | }, 30 | "sslverify": &schema.Schema{ 31 | Type: schema.TypeBool, 32 | Required: true, 33 | DefaultFunc: schema.EnvDefaultFunc("INFOBLOX_SSLVERIFY", true), 34 | Description: "Enable ssl", 35 | }, 36 | "usecookies": &schema.Schema{ 37 | Type: schema.TypeBool, 38 | Required: true, 39 | DefaultFunc: schema.EnvDefaultFunc("INFOBLOX_USECOOKIES", false), 40 | Description: "Use cookies", 41 | }, 42 | }, 43 | 44 | ResourcesMap: map[string]*schema.Resource{ 45 | "infoblox_record": resourceInfobloxRecord(), 46 | "infoblox_ip": resourceInfobloxIP(), 47 | 48 | "infoblox_record_a": infobloxRecordA(), 49 | "infoblox_record_aaaa": infobloxRecordAAAA(), 50 | "infoblox_record_cname": infobloxRecordCNAME(), 51 | "infoblox_record_ptr": infobloxRecordPTR(), 52 | "infoblox_record_host": infobloxRecordHost(), 53 | "infoblox_record_txt": infobloxRecordTXT(), 54 | "infoblox_record_mx": infobloxRecordMX(), 55 | "infoblox_record_srv": infobloxRecordSRV(), 56 | }, 57 | 58 | ConfigureFunc: provideConfigure, 59 | } 60 | } 61 | 62 | func provideConfigure(d *schema.ResourceData) (interface{}, error) { 63 | config := Config{ 64 | Username: d.Get("username").(string), 65 | Password: d.Get("password").(string), 66 | Host: d.Get("host").(string), 67 | SSLVerify: d.Get("sslverify").(bool), 68 | UseCookies: d.Get("usecookies").(bool), 69 | } 70 | 71 | return config.Client() 72 | } 73 | -------------------------------------------------------------------------------- /infoblox/helpers.go: -------------------------------------------------------------------------------- 1 | package infoblox 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "net/url" 7 | "strconv" 8 | "strings" 9 | 10 | "github.com/fanatic/go-infoblox" 11 | "github.com/hashicorp/terraform/helper/schema" 12 | ) 13 | 14 | // The comment, ttl, and, view attributes are common across all of the DNS 15 | // record objects we deal with so far so we extract populating them into the 16 | // url.Values object into a helper function. 17 | func populateSharedAttributes(d *schema.ResourceData, record *url.Values) { 18 | if attr, ok := d.GetOk("comment"); ok { 19 | record.Set("comment", attr.(string)) 20 | } 21 | 22 | if attr, ok := d.GetOk("ttl"); ok { 23 | record.Set("ttl", strconv.Itoa(attr.(int))) 24 | } 25 | 26 | if attr, ok := d.GetOk("view"); ok { 27 | record.Set("view", attr.(string)) 28 | } 29 | } 30 | 31 | // Parses the given string as an ip address and returns "ipv4addr" if it is an 32 | // ipv4 address and "ipv6addr" if it is an ipv6 address 33 | func ipType(value string) (string, error) { 34 | ip := net.ParseIP(value) 35 | if ip == nil { 36 | return "", fmt.Errorf("value does not appear to be a valid ip address") 37 | } 38 | 39 | res := "ipv6addr" 40 | if ip.To4() != nil { 41 | res = "ipv4addr" 42 | } 43 | return res, nil 44 | } 45 | 46 | // Finds networks by search term, such as network CIDR. 47 | func getNetworks(client *infoblox.Client, term string) ([]map[string]interface{}, error) { 48 | s := "network" 49 | q := []infoblox.Condition{ 50 | infoblox.Condition{ 51 | Field: &s, 52 | Value: term, 53 | }, 54 | } 55 | 56 | network, err := client.Network().Find(q, nil) 57 | return network, err 58 | } 59 | 60 | // Builds an array of IP addresses to exclude from terraform resource data. 61 | func buildExcludedAddressesArray(d *schema.ResourceData) []string { 62 | var excludedAddresses []string 63 | if userExcludes := d.Get("exclude"); userExcludes != nil { 64 | addresses := userExcludes.(*schema.Set).List() 65 | for _, address := range addresses { 66 | excludedAddresses = append(excludedAddresses, address.(string)) 67 | } 68 | } 69 | return excludedAddresses 70 | } 71 | 72 | // TODO: I'm positive there's a better way to do this, but this works for now 73 | func getMapValueAsString(mymap map[string]interface{}, val string) string { 74 | for k, v := range mymap { 75 | if k == val { 76 | vout := fmt.Sprintf("%q", v) 77 | vout = strings.Replace(vout, "[", "", -1) 78 | vout = strings.Replace(vout, "]", "", -1) 79 | vout = strings.Replace(vout, "\"", "", -1) 80 | return vout 81 | } 82 | } 83 | 84 | return "" 85 | } 86 | 87 | // Validates that either 'cidr' or 'ip_range' terraform argument is set. 88 | func validateIPData(d *schema.ResourceData) error { 89 | _, cidrOk := d.GetOk("cidr") 90 | _, ipRangeOk := d.GetOk("ip_range") 91 | if !cidrOk && !ipRangeOk { 92 | return fmt.Errorf( 93 | "One of ['cidr', 'ip_range'] must be set to create an Infoblox IP") 94 | } 95 | return nil 96 | } 97 | 98 | func handleReadError(d *schema.ResourceData, recordType string, err error) error { 99 | if infobloxErr, ok := err.(infoblox.Error); ok { 100 | if infobloxErr.Code() == "Client.Ibap.Data.NotFound" { 101 | d.SetId("") 102 | return nil 103 | } 104 | } 105 | return fmt.Errorf("Error reading Infoblox %s record: %s", recordType, err) 106 | } 107 | -------------------------------------------------------------------------------- /infoblox/resource_infoblox_record_txt.go: -------------------------------------------------------------------------------- 1 | package infoblox 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | 8 | infoblox "github.com/fanatic/go-infoblox" 9 | "github.com/hashicorp/terraform/helper/schema" 10 | ) 11 | 12 | func infobloxRecordTXT() *schema.Resource { 13 | return &schema.Resource{ 14 | Create: resourceInfobloxTXTRecordCreate, 15 | Read: resourceInfobloxTXTRecordRead, 16 | Update: resourceInfobloxTXTRecordUpdate, 17 | Delete: resourceInfobloxTXTRecordDelete, 18 | 19 | Schema: map[string]*schema.Schema{ 20 | "name": &schema.Schema{ 21 | Type: schema.TypeString, 22 | Required: true, 23 | ForceNew: true, 24 | }, 25 | "text": &schema.Schema{ 26 | Type: schema.TypeString, 27 | Required: true, 28 | ForceNew: false, 29 | }, 30 | "comment": &schema.Schema{ 31 | Type: schema.TypeString, 32 | Optional: true, 33 | Default: "", 34 | }, 35 | "ttl": &schema.Schema{ 36 | Type: schema.TypeInt, 37 | Optional: true, 38 | }, 39 | "view": &schema.Schema{ 40 | Type: schema.TypeString, 41 | Optional: true, 42 | }, 43 | }, 44 | } 45 | } 46 | 47 | func resourceInfobloxTXTRecordCreate(d *schema.ResourceData, meta interface{}) error { 48 | client := meta.(*infoblox.Client) 49 | 50 | record := url.Values{} 51 | record.Add("name", d.Get("name").(string)) 52 | record.Add("text", d.Get("text").(string)) 53 | populateSharedAttributes(d, &record) 54 | 55 | log.Printf("[DEBUG] Creating Infoblox TXT record with configuration: %#v", record) 56 | 57 | opts := &infoblox.Options{ 58 | ReturnFields: []string{"name", "text", "comment", "ttl", "view"}, 59 | } 60 | 61 | recordID, err := client.RecordTxt().Create(record, opts, nil) 62 | 63 | if err != nil { 64 | return fmt.Errorf("error creating infoblox TXT record: %s", err.Error()) 65 | } 66 | 67 | d.SetId(recordID) 68 | log.Printf("[INFO] Infoblox TXT record created with ID: %s", d.Id()) 69 | 70 | return nil 71 | } 72 | 73 | func resourceInfobloxTXTRecordRead(d *schema.ResourceData, meta interface{}) error { 74 | client := meta.(*infoblox.Client) 75 | 76 | opts := &infoblox.Options{ 77 | ReturnFields: []string{"name", "text", "comment", "ttl", "view"}, 78 | } 79 | record, err := client.GetRecordTxt(d.Id(), opts) 80 | if err != nil { 81 | return handleReadError(d, "TXT", err) 82 | } 83 | 84 | d.Set("name", record.Name) 85 | d.Set("text", record.Text) 86 | 87 | if &record.Comment != nil { 88 | d.Set("comment", record.Comment) 89 | } 90 | if &record.Ttl != nil { 91 | d.Set("ttl", record.Ttl) 92 | } 93 | if &record.View != nil { 94 | d.Set("view", record.View) 95 | } 96 | 97 | return nil 98 | } 99 | 100 | func resourceInfobloxTXTRecordUpdate(d *schema.ResourceData, meta interface{}) error { 101 | client := meta.(*infoblox.Client) 102 | 103 | opts := &infoblox.Options{ 104 | ReturnFields: []string{"name", "text", "comment", "ttl", "view"}, 105 | } 106 | _, err := client.GetRecordTxt(d.Id(), opts) 107 | if err != nil { 108 | return fmt.Errorf("error finding infoblox TXT record: %s", err.Error()) 109 | } 110 | 111 | record := url.Values{} 112 | record.Add("name", d.Get("name").(string)) 113 | record.Add("text", d.Get("text").(string)) 114 | populateSharedAttributes(d, &record) 115 | 116 | log.Printf("[DEBUG] Updating Infoblox TXT record with configuration: %#v", record) 117 | 118 | recordID, err := client.RecordTxtObject(d.Id()).Update(record, opts, nil) 119 | if err != nil { 120 | return fmt.Errorf("error updating Infoblox TXT record: %s", err.Error()) 121 | } 122 | 123 | d.SetId(recordID) 124 | log.Printf("[INFO] Infoblox TXT record updated with ID: %s", d.Id()) 125 | 126 | return resourceInfobloxTXTRecordRead(d, meta) 127 | } 128 | 129 | func resourceInfobloxTXTRecordDelete(d *schema.ResourceData, meta interface{}) error { 130 | client := meta.(*infoblox.Client) 131 | 132 | log.Printf("[DEBUG] Deleting Infoblox TXT record: %s, %s", d.Get("name").(string), d.Id()) 133 | _, err := client.GetRecordTxt(d.Id(), nil) 134 | if err != nil { 135 | return fmt.Errorf("error finding Infoblox TXT record: %s", err.Error()) 136 | } 137 | 138 | err = client.RecordTxtObject(d.Id()).Delete(nil) 139 | if err != nil { 140 | return fmt.Errorf("error deleting Infoblox TXT record: %s", err.Error()) 141 | } 142 | 143 | return nil 144 | } 145 | -------------------------------------------------------------------------------- /infoblox/resource_infoblox_record_cname.go: -------------------------------------------------------------------------------- 1 | package infoblox 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | 8 | infoblox "github.com/fanatic/go-infoblox" 9 | "github.com/hashicorp/terraform/helper/schema" 10 | ) 11 | 12 | func infobloxRecordCNAME() *schema.Resource { 13 | return &schema.Resource{ 14 | Create: resourceInfobloxCNAMERecordCreate, 15 | Read: resourceInfobloxCNAMERecordRead, 16 | Update: resourceInfobloxCNAMERecordUpdate, 17 | Delete: resourceInfobloxCNAMERecordDelete, 18 | 19 | Schema: map[string]*schema.Schema{ 20 | "canonical": &schema.Schema{ 21 | Type: schema.TypeString, 22 | Required: true, 23 | ForceNew: true, 24 | }, 25 | "name": &schema.Schema{ 26 | Type: schema.TypeString, 27 | Required: true, 28 | ForceNew: true, 29 | }, 30 | "comment": &schema.Schema{ 31 | Type: schema.TypeString, 32 | Optional: true, 33 | Default: "", 34 | }, 35 | "ttl": &schema.Schema{ 36 | Type: schema.TypeInt, 37 | Optional: true, 38 | }, 39 | "view": &schema.Schema{ 40 | Type: schema.TypeString, 41 | Optional: true, 42 | }, 43 | }, 44 | } 45 | } 46 | 47 | func resourceInfobloxCNAMERecordCreate(d *schema.ResourceData, meta interface{}) error { 48 | client := meta.(*infoblox.Client) 49 | 50 | record := url.Values{} 51 | record.Add("canonical", d.Get("canonical").(string)) 52 | record.Add("name", d.Get("name").(string)) 53 | populateSharedAttributes(d, &record) 54 | 55 | log.Printf("[DEBUG] Creating Infoblox CNAME record with configuration: %#v", record) 56 | 57 | opts := &infoblox.Options{ 58 | ReturnFields: []string{"canonical", "name", "comment", "ttl", "view"}, 59 | } 60 | recordID, err := client.RecordCname().Create(record, opts, nil) 61 | if err != nil { 62 | return fmt.Errorf("error creating infoblox CNAME record: %s", err.Error()) 63 | } 64 | 65 | d.SetId(recordID) 66 | log.Printf("[INFO] Infoblox CNAME record created with ID: %s", d.Id()) 67 | 68 | return nil 69 | } 70 | 71 | func resourceInfobloxCNAMERecordRead(d *schema.ResourceData, meta interface{}) error { 72 | client := meta.(*infoblox.Client) 73 | 74 | opts := &infoblox.Options{ 75 | ReturnFields: []string{"canonical", "name", "comment", "ttl", "view"}, 76 | } 77 | record, err := client.GetRecordCname(d.Id(), opts) 78 | if err != nil { 79 | return handleReadError(d, "CNAME", err) 80 | } 81 | 82 | d.Set("canonical", record.Canonical) 83 | d.Set("name", record.Name) 84 | 85 | if &record.Comment != nil { 86 | d.Set("comment", record.Comment) 87 | } 88 | if &record.Ttl != nil { 89 | d.Set("ttl", record.Ttl) 90 | } 91 | if &record.View != nil { 92 | d.Set("view", record.View) 93 | } 94 | 95 | return nil 96 | } 97 | 98 | func resourceInfobloxCNAMERecordUpdate(d *schema.ResourceData, meta interface{}) error { 99 | client := meta.(*infoblox.Client) 100 | 101 | opts := &infoblox.Options{ 102 | ReturnFields: []string{"canonical", "name", "comment", "ttl", "view"}, 103 | } 104 | _, err := client.GetRecordCname(d.Id(), opts) 105 | if err != nil { 106 | return fmt.Errorf("error finding infoblox CNAME record: %s", err.Error()) 107 | } 108 | 109 | record := url.Values{} 110 | record.Add("canonical", d.Get("canonical").(string)) 111 | record.Add("name", d.Get("name").(string)) 112 | populateSharedAttributes(d, &record) 113 | 114 | log.Printf("[DEBUG] Updating Infoblox CNAME record with configuration: %#v", record) 115 | 116 | recordID, err := client.RecordCnameObject(d.Id()).Update(record, opts, nil) 117 | if err != nil { 118 | return fmt.Errorf("error updating Infoblox CNAME record: %s", err.Error()) 119 | } 120 | 121 | d.SetId(recordID) 122 | log.Printf("[INFO] Infoblox CNAME record updated with ID: %s", d.Id()) 123 | 124 | return resourceInfobloxCNAMERecordRead(d, meta) 125 | } 126 | 127 | func resourceInfobloxCNAMERecordDelete(d *schema.ResourceData, meta interface{}) error { 128 | client := meta.(*infoblox.Client) 129 | 130 | log.Printf("[DEBUG] Deleting Infoblox CNAME record: %s, %s", d.Get("name").(string), d.Id()) 131 | _, err := client.GetRecordCname(d.Id(), nil) 132 | if err != nil { 133 | return fmt.Errorf("error finding Infoblox CNAME record: %s", err.Error()) 134 | } 135 | 136 | err = client.RecordCnameObject(d.Id()).Delete(nil) 137 | if err != nil { 138 | return fmt.Errorf("error deleting Infoblox CNAME record: %s", err.Error()) 139 | } 140 | 141 | return nil 142 | } 143 | -------------------------------------------------------------------------------- /infoblox/resource_infoblox_record_aaaa.go: -------------------------------------------------------------------------------- 1 | package infoblox 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | 8 | infoblox "github.com/fanatic/go-infoblox" 9 | "github.com/hashicorp/terraform/helper/schema" 10 | ) 11 | 12 | func infobloxRecordAAAA() *schema.Resource { 13 | return &schema.Resource{ 14 | Create: resourceInfobloxAAAARecordCreate, 15 | Read: resourceInfobloxAAAARecordRead, 16 | Update: resourceInfobloxAAAARecordUpdate, 17 | Delete: resourceInfobloxAAAARecordDelete, 18 | 19 | Schema: map[string]*schema.Schema{ 20 | // TODO: validate that address is in IPv6 format. 21 | "address": &schema.Schema{ 22 | Type: schema.TypeString, 23 | Required: true, 24 | ForceNew: true, 25 | }, 26 | "name": &schema.Schema{ 27 | Type: schema.TypeString, 28 | Required: true, 29 | ForceNew: true, 30 | }, 31 | "comment": &schema.Schema{ 32 | Type: schema.TypeString, 33 | Optional: true, 34 | Default: "", 35 | }, 36 | "ttl": &schema.Schema{ 37 | Type: schema.TypeInt, 38 | Optional: true, 39 | }, 40 | "view": &schema.Schema{ 41 | Type: schema.TypeString, 42 | Optional: true, 43 | }, 44 | }, 45 | } 46 | } 47 | 48 | func resourceInfobloxAAAARecordCreate(d *schema.ResourceData, meta interface{}) error { 49 | client := meta.(*infoblox.Client) 50 | 51 | record := url.Values{} 52 | record.Add("ipv6addr", d.Get("address").(string)) 53 | record.Add("name", d.Get("name").(string)) 54 | populateSharedAttributes(d, &record) 55 | 56 | log.Printf("[DEBUG] Creating Infoblox AAAA record with configuration: %#v", record) 57 | 58 | opts := &infoblox.Options{ 59 | ReturnFields: []string{"ipv6addr", "name", "comment", "ttl", "view"}, 60 | } 61 | recordID, err := client.RecordAAAA().Create(record, opts, nil) 62 | 63 | if err != nil { 64 | return fmt.Errorf("error creating infoblox AAAA record: %s", err.Error()) 65 | } 66 | 67 | d.SetId(recordID) 68 | log.Printf("[INFO] Infoblox AAAA record created with ID: %s", d.Id()) 69 | 70 | return nil 71 | } 72 | 73 | func resourceInfobloxAAAARecordRead(d *schema.ResourceData, meta interface{}) error { 74 | client := meta.(*infoblox.Client) 75 | 76 | opts := &infoblox.Options{ 77 | ReturnFields: []string{"ipv6addr", "name", "comment", "ttl", "view"}, 78 | } 79 | record, err := client.GetRecordAAAA(d.Id(), opts) 80 | if err != nil { 81 | return handleReadError(d, "AAAA", err) 82 | } 83 | 84 | d.Set("address", record.Ipv6Addr) 85 | d.Set("name", record.Name) 86 | 87 | if &record.Comment != nil { 88 | d.Set("comment", record.Comment) 89 | } 90 | if &record.Ttl != nil { 91 | d.Set("ttl", record.Ttl) 92 | } 93 | if &record.View != nil { 94 | d.Set("view", record.View) 95 | } 96 | 97 | return nil 98 | } 99 | 100 | func resourceInfobloxAAAARecordUpdate(d *schema.ResourceData, meta interface{}) error { 101 | client := meta.(*infoblox.Client) 102 | 103 | opts := &infoblox.Options{ 104 | ReturnFields: []string{"ipv6addr", "name", "comment", "ttl", "view"}, 105 | } 106 | _, err := client.GetRecordAAAA(d.Id(), opts) 107 | if err != nil { 108 | return fmt.Errorf("error finding infoblox AAAA record: %s", err.Error()) 109 | } 110 | 111 | record := url.Values{} 112 | record.Add("ipv6addr", d.Get("address").(string)) 113 | record.Add("name", d.Get("name").(string)) 114 | populateSharedAttributes(d, &record) 115 | 116 | log.Printf("[DEBUG] Updating Infoblox AAAA record with configuration: %#v", record) 117 | 118 | recordID, err := client.RecordAAAAObject(d.Id()).Update(record, opts, nil) 119 | if err != nil { 120 | return fmt.Errorf("error updating Infoblox AAAA record: %s", err.Error()) 121 | } 122 | 123 | d.SetId(recordID) 124 | log.Printf("[INFO] Infoblox AAAA record updated with ID: %s", d.Id()) 125 | 126 | return resourceInfobloxAAAARecordRead(d, meta) 127 | } 128 | 129 | func resourceInfobloxAAAARecordDelete(d *schema.ResourceData, meta interface{}) error { 130 | client := meta.(*infoblox.Client) 131 | 132 | log.Printf("[DEBUG] Deleting Infoblox AAAA record: %s, %s", d.Get("name").(string), d.Id()) 133 | _, err := client.GetRecordAAAA(d.Id(), nil) 134 | if err != nil { 135 | return fmt.Errorf("error finding Infoblox AAAA record: %s", err.Error()) 136 | } 137 | 138 | err = client.RecordAAAAObject(d.Id()).Delete(nil) 139 | if err != nil { 140 | return fmt.Errorf("error deleting Infoblox AAAA record: %s", err.Error()) 141 | } 142 | 143 | return nil 144 | } 145 | -------------------------------------------------------------------------------- /infoblox/resource_infoblox_record_mx.go: -------------------------------------------------------------------------------- 1 | package infoblox 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | "strconv" 8 | 9 | infoblox "github.com/fanatic/go-infoblox" 10 | "github.com/hashicorp/terraform/helper/schema" 11 | ) 12 | 13 | func infobloxRecordMX() *schema.Resource { 14 | return &schema.Resource{ 15 | Create: resourceInfobloxMXRecordCreate, 16 | Read: resourceInfobloxMXRecordRead, 17 | Update: resourceInfobloxMXRecordUpdate, 18 | Delete: resourceInfobloxMXRecordDelete, 19 | 20 | Schema: map[string]*schema.Schema{ 21 | "exchanger": &schema.Schema{ 22 | Type: schema.TypeString, 23 | Required: true, 24 | ForceNew: true, 25 | }, 26 | "name": &schema.Schema{ 27 | Type: schema.TypeString, 28 | Required: true, 29 | ForceNew: true, 30 | }, 31 | "pref": &schema.Schema{ 32 | Type: schema.TypeInt, 33 | Required: true, 34 | ForceNew: false, 35 | }, 36 | "comment": &schema.Schema{ 37 | Type: schema.TypeString, 38 | Optional: true, 39 | Default: "", 40 | }, 41 | "ttl": &schema.Schema{ 42 | Type: schema.TypeInt, 43 | Optional: true, 44 | }, 45 | "view": &schema.Schema{ 46 | Type: schema.TypeString, 47 | Optional: true, 48 | }, 49 | }, 50 | } 51 | } 52 | 53 | func resourceInfobloxMXRecordCreate(d *schema.ResourceData, meta interface{}) error { 54 | client := meta.(*infoblox.Client) 55 | 56 | record := url.Values{} 57 | record.Add("exchanger", d.Get("exchanger").(string)) 58 | record.Add("name", d.Get("name").(string)) 59 | record.Add("pref", strconv.Itoa(d.Get("pref").(int))) 60 | populateSharedAttributes(d, &record) 61 | 62 | log.Printf("[DEBUG] Creating Infoblox MX record with configuration: %#v", record) 63 | 64 | opts := &infoblox.Options{ 65 | ReturnFields: []string{"exchanger", "name", "pref", "comment", "ttl", "view"}, 66 | } 67 | 68 | // TODO: Add MX support to go-infoblox 69 | recordID, err := client.RecordMx().Create(record, opts, nil) 70 | 71 | if err != nil { 72 | return fmt.Errorf("error creating infoblox MX record: %s", err.Error()) 73 | } 74 | 75 | d.SetId(recordID) 76 | log.Printf("[INFO] Infoblox MX record created with ID: %s", d.Id()) 77 | 78 | return nil 79 | } 80 | 81 | func resourceInfobloxMXRecordRead(d *schema.ResourceData, meta interface{}) error { 82 | client := meta.(*infoblox.Client) 83 | 84 | opts := &infoblox.Options{ 85 | ReturnFields: []string{"exchanger", "name", "pref", "comment", "ttl", "view"}, 86 | } 87 | record, err := client.GetRecordMx(d.Id(), opts) 88 | if err != nil { 89 | return handleReadError(d, "MX", err) 90 | } 91 | 92 | d.Set("exchanger", record.Exchanger) 93 | d.Set("name", record.Name) 94 | d.Set("pref", record.Pref) 95 | 96 | if &record.Comment != nil { 97 | d.Set("comment", record.Comment) 98 | } 99 | if &record.Ttl != nil { 100 | d.Set("ttl", record.Ttl) 101 | } 102 | if &record.View != nil { 103 | d.Set("view", record.View) 104 | } 105 | 106 | return nil 107 | } 108 | 109 | func resourceInfobloxMXRecordUpdate(d *schema.ResourceData, meta interface{}) error { 110 | client := meta.(*infoblox.Client) 111 | 112 | opts := &infoblox.Options{ 113 | ReturnFields: []string{"exchanger", "name", "pref", "comment", "ttl", "view"}, 114 | } 115 | _, err := client.GetRecordMx(d.Id(), opts) 116 | if err != nil { 117 | return fmt.Errorf("error finding infoblox MX record: %s", err.Error()) 118 | } 119 | 120 | record := url.Values{} 121 | record.Add("exchanger", d.Get("address").(string)) 122 | record.Add("name", d.Get("name").(string)) 123 | record.Add("pref", strconv.Itoa(d.Get("pref").(int))) 124 | populateSharedAttributes(d, &record) 125 | 126 | log.Printf("[DEBUG] Updating Infoblox MX record with configuration: %#v", record) 127 | 128 | recordID, err := client.RecordMxObject(d.Id()).Update(record, opts, nil) 129 | if err != nil { 130 | return fmt.Errorf("error updating Infoblox MX record: %s", err.Error()) 131 | } 132 | 133 | d.SetId(recordID) 134 | log.Printf("[INFO] Infoblox MX record updated with ID: %s", d.Id()) 135 | 136 | return resourceInfobloxMXRecordRead(d, meta) 137 | } 138 | 139 | func resourceInfobloxMXRecordDelete(d *schema.ResourceData, meta interface{}) error { 140 | client := meta.(*infoblox.Client) 141 | 142 | log.Printf("[DEBUG] Deleting Infoblox MX record: %s, %s", d.Get("name").(string), d.Id()) 143 | _, err := client.GetRecordMx(d.Id(), nil) 144 | if err != nil { 145 | return fmt.Errorf("error finding Infoblox MX record: %s", err.Error()) 146 | } 147 | 148 | err = client.RecordMxObject(d.Id()).Delete(nil) 149 | if err != nil { 150 | return fmt.Errorf("error deleting Infoblox MX record: %s", err.Error()) 151 | } 152 | 153 | return nil 154 | } 155 | -------------------------------------------------------------------------------- /infoblox/resource_infoblox_record_a.go: -------------------------------------------------------------------------------- 1 | package infoblox 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | 8 | infoblox "github.com/fanatic/go-infoblox" 9 | "github.com/hashicorp/terraform/helper/schema" 10 | ) 11 | 12 | func infobloxRecordA() *schema.Resource { 13 | return &schema.Resource{ 14 | Create: resourceInfobloxARecordCreate, 15 | Read: resourceInfobloxARecordRead, 16 | Update: resourceInfobloxARecordUpdate, 17 | Delete: resourceInfobloxARecordDelete, 18 | 19 | Schema: map[string]*schema.Schema{ 20 | // TODO: validate that address is in IPv4 format. 21 | "address": &schema.Schema{ 22 | Type: schema.TypeString, 23 | Required: true, 24 | ForceNew: true, 25 | }, 26 | "name": &schema.Schema{ 27 | Type: schema.TypeString, 28 | Required: true, 29 | ForceNew: true, 30 | }, 31 | "comment": &schema.Schema{ 32 | Type: schema.TypeString, 33 | Optional: true, 34 | }, 35 | "ttl": &schema.Schema{ 36 | Type: schema.TypeInt, 37 | Optional: true, 38 | }, 39 | "view": &schema.Schema{ 40 | Type: schema.TypeString, 41 | Optional: true, 42 | Default: "default", 43 | }, 44 | }, 45 | } 46 | } 47 | 48 | // aObjectFromAttributes created an infoblox.RecordAObject using the attributes 49 | // as set by terraform. 50 | // The Infoblox WAPI does not allow updates to the "view" field on an A record, 51 | // so we also take a skipView arg to skip setting view. 52 | func aObjectFromAttributes(d *schema.ResourceData, skipView bool) infoblox.RecordAObject { 53 | aObject := infoblox.RecordAObject{} 54 | 55 | aObject.Name = d.Get("name").(string) 56 | aObject.Ipv4Addr = d.Get("address").(string) 57 | 58 | if attr, ok := d.GetOk("comment"); ok { 59 | aObject.Comment = attr.(string) 60 | } 61 | if attr, ok := d.GetOk("ttl"); ok { 62 | aObject.Ttl = attr.(int) 63 | } 64 | if skipView { 65 | return aObject 66 | } 67 | 68 | if attr, ok := d.GetOk("view"); ok { 69 | aObject.View = attr.(string) 70 | } 71 | 72 | return aObject 73 | } 74 | 75 | func resourceInfobloxARecordCreate(d *schema.ResourceData, meta interface{}) error { 76 | client := meta.(*infoblox.Client) 77 | 78 | record := url.Values{} 79 | aRecordObject := aObjectFromAttributes(d, false) 80 | 81 | log.Printf("[DEBUG] Creating Infoblox A record with configuration: %#v", aRecordObject) 82 | 83 | opts := &infoblox.Options{ 84 | ReturnFields: []string{"ipv4addr", "name", "comment", "ttl", "view"}, 85 | } 86 | recordID, err := client.RecordA().Create(record, opts, aRecordObject) 87 | if err != nil { 88 | return fmt.Errorf("error creating infoblox A record: %s", err.Error()) 89 | } 90 | 91 | d.SetId(recordID) 92 | log.Printf("[INFO] Infoblox A record created with ID: %s", d.Id()) 93 | 94 | return resourceInfobloxARecordRead(d, meta) 95 | } 96 | 97 | func resourceInfobloxARecordRead(d *schema.ResourceData, meta interface{}) error { 98 | client := meta.(*infoblox.Client) 99 | 100 | opts := &infoblox.Options{ 101 | ReturnFields: []string{"ipv4addr", "name", "comment", "ttl", "view"}, 102 | } 103 | record, err := client.GetRecordA(d.Id(), opts) 104 | if err != nil { 105 | return handleReadError(d, "A", err) 106 | } 107 | 108 | d.Set("address", record.Ipv4Addr) 109 | d.Set("name", record.Name) 110 | d.Set("comment", record.Comment) 111 | d.Set("ttl", record.Ttl) 112 | d.Set("view", record.View) 113 | 114 | return nil 115 | } 116 | 117 | func resourceInfobloxARecordUpdate(d *schema.ResourceData, meta interface{}) error { 118 | client := meta.(*infoblox.Client) 119 | 120 | opts := &infoblox.Options{ 121 | ReturnFields: []string{"ipv4addr", "name", "comment", "ttl", "view"}, 122 | } 123 | _, err := client.GetRecordA(d.Id(), opts) 124 | if err != nil { 125 | return fmt.Errorf("error finding infoblox A record: %s", err.Error()) 126 | } 127 | 128 | record := url.Values{} 129 | aRecordObject := aObjectFromAttributes(d, true) 130 | 131 | log.Printf("[DEBUG] Updating Infoblox A record with configuration: %#v", record) 132 | 133 | recordID, err := client.RecordAObject(d.Id()).Update(record, opts, aRecordObject) 134 | if err != nil { 135 | return fmt.Errorf("error updating Infoblox A record: %s", err.Error()) 136 | } 137 | 138 | d.SetId(recordID) 139 | log.Printf("[INFO] Infoblox A record updated with ID: %s", d.Id()) 140 | 141 | return resourceInfobloxARecordRead(d, meta) 142 | } 143 | 144 | func resourceInfobloxARecordDelete(d *schema.ResourceData, meta interface{}) error { 145 | client := meta.(*infoblox.Client) 146 | 147 | log.Printf("[DEBUG] Deleting Infoblox A record: %s, %s", d.Get("name").(string), d.Id()) 148 | _, err := client.GetRecordA(d.Id(), nil) 149 | if err != nil { 150 | return fmt.Errorf("error finding Infoblox A record: %s", err.Error()) 151 | } 152 | 153 | err = client.RecordAObject(d.Id()).Delete(nil) 154 | if err != nil { 155 | return fmt.Errorf("error deleting Infoblox A record: %s", err.Error()) 156 | } 157 | 158 | return nil 159 | } 160 | -------------------------------------------------------------------------------- /infoblox/resource_infoblox_record_srv.go: -------------------------------------------------------------------------------- 1 | package infoblox 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | "strconv" 8 | 9 | infoblox "github.com/fanatic/go-infoblox" 10 | "github.com/hashicorp/terraform/helper/schema" 11 | ) 12 | 13 | func infobloxRecordSRV() *schema.Resource { 14 | return &schema.Resource{ 15 | Create: resourceInfobloxSRVRecordCreate, 16 | Read: resourceInfobloxSRVRecordRead, 17 | Update: resourceInfobloxSRVRecordUpdate, 18 | Delete: resourceInfobloxSRVRecordDelete, 19 | 20 | Schema: map[string]*schema.Schema{ 21 | "name": &schema.Schema{ 22 | Type: schema.TypeString, 23 | Required: true, 24 | ForceNew: true, 25 | }, 26 | "port": &schema.Schema{ 27 | Type: schema.TypeInt, 28 | Required: true, 29 | ForceNew: false, 30 | }, 31 | "priority": &schema.Schema{ 32 | Type: schema.TypeInt, 33 | Required: true, 34 | ForceNew: false, 35 | }, 36 | "target": &schema.Schema{ 37 | Type: schema.TypeString, 38 | Optional: true, 39 | Default: "", 40 | }, 41 | "weight": &schema.Schema{ 42 | Type: schema.TypeInt, 43 | Required: true, 44 | ForceNew: false, 45 | }, 46 | "comment": &schema.Schema{ 47 | Type: schema.TypeString, 48 | Optional: true, 49 | Default: "", 50 | }, 51 | "ttl": &schema.Schema{ 52 | Type: schema.TypeInt, 53 | Optional: true, 54 | }, 55 | "view": &schema.Schema{ 56 | Type: schema.TypeString, 57 | Optional: true, 58 | }, 59 | }, 60 | } 61 | } 62 | 63 | func resourceInfobloxSRVRecordCreate(d *schema.ResourceData, meta interface{}) error { 64 | client := meta.(*infoblox.Client) 65 | 66 | record := url.Values{} 67 | record.Add("name", d.Get("name").(string)) 68 | record.Add("port", strconv.Itoa(d.Get("port").(int))) 69 | record.Add("priority", strconv.Itoa(d.Get("priority").(int))) 70 | record.Add("target", d.Get("target").(string)) 71 | record.Add("weight", strconv.Itoa(d.Get("weight").(int))) 72 | populateSharedAttributes(d, &record) 73 | 74 | log.Printf("[DEBUG] Creating Infoblox SRV record with configuration: %#v", record) 75 | 76 | opts := &infoblox.Options{ 77 | ReturnFields: []string{"name", "port", "priority", "target", "weight", "comment", "ttl", "view"}, 78 | } 79 | 80 | // TODO: Add SRV support to go-infoblox 81 | recordID, err := client.RecordSrv().Create(record, opts, nil) 82 | 83 | if err != nil { 84 | return fmt.Errorf("error creating infoblox SRV record: %s", err.Error()) 85 | } 86 | 87 | d.SetId(recordID) 88 | log.Printf("[INFO] Infoblox SRV record created with ID: %s", d.Id()) 89 | 90 | return nil 91 | } 92 | 93 | func resourceInfobloxSRVRecordRead(d *schema.ResourceData, meta interface{}) error { 94 | client := meta.(*infoblox.Client) 95 | 96 | opts := &infoblox.Options{ 97 | ReturnFields: []string{"name", "port", "priority", "target", "weight", "comment", "ttl", "view"}, 98 | } 99 | record, err := client.GetRecordSrv(d.Id(), opts) 100 | if err != nil { 101 | return handleReadError(d, "SRV", err) 102 | } 103 | 104 | d.Set("name", record.Name) 105 | d.Set("port", record.Port) 106 | d.Set("priority", record.Priority) 107 | d.Set("target", record.Target) 108 | d.Set("weight", record.Weight) 109 | 110 | if &record.Comment != nil { 111 | d.Set("comment", record.Comment) 112 | } 113 | if &record.Ttl != nil { 114 | d.Set("ttl", record.Ttl) 115 | } 116 | if &record.View != nil { 117 | d.Set("view", record.View) 118 | } 119 | 120 | return nil 121 | } 122 | 123 | func resourceInfobloxSRVRecordUpdate(d *schema.ResourceData, meta interface{}) error { 124 | client := meta.(*infoblox.Client) 125 | 126 | opts := &infoblox.Options{ 127 | ReturnFields: []string{"name", "port", "priority", "target", "weight", "comment", "ttl", "view"}, 128 | } 129 | _, err := client.GetRecordSrv(d.Id(), opts) 130 | if err != nil { 131 | return fmt.Errorf("error finding infoblox SRV record: %s", err.Error()) 132 | } 133 | 134 | record := url.Values{} 135 | // name string 136 | // port int 137 | // priority int 138 | // target fqdn/string 139 | // weight int 140 | // shared 141 | record.Add("name", d.Get("name").(string)) 142 | record.Add("port", strconv.Itoa(d.Get("port").(int))) 143 | record.Add("priority", strconv.Itoa(d.Get("priority").(int))) 144 | record.Add("target", d.Get("target").(string)) 145 | record.Add("weight", strconv.Itoa(d.Get("weight").(int))) 146 | populateSharedAttributes(d, &record) 147 | 148 | log.Printf("[DEBUG] Updating Infoblox SRV record with configuration: %#v", record) 149 | 150 | recordID, err := client.RecordSrvObject(d.Id()).Update(record, opts, nil) 151 | if err != nil { 152 | return fmt.Errorf("error updating Infoblox SRV record: %s", err.Error()) 153 | } 154 | 155 | d.SetId(recordID) 156 | log.Printf("[INFO] Infoblox SRV record updated with ID: %s", d.Id()) 157 | 158 | return resourceInfobloxSRVRecordRead(d, meta) 159 | } 160 | 161 | func resourceInfobloxSRVRecordDelete(d *schema.ResourceData, meta interface{}) error { 162 | client := meta.(*infoblox.Client) 163 | 164 | log.Printf("[DEBUG] Deleting Infoblox SRV record: %s, %s", d.Get("name").(string), d.Id()) 165 | _, err := client.GetRecordSrv(d.Id(), nil) 166 | if err != nil { 167 | return fmt.Errorf("error finding Infoblox SRV record: %s", err.Error()) 168 | } 169 | 170 | err = client.RecordSrvObject(d.Id()).Delete(nil) 171 | if err != nil { 172 | return fmt.Errorf("error deleting Infoblox SRV record: %s", err.Error()) 173 | } 174 | 175 | return nil 176 | } 177 | -------------------------------------------------------------------------------- /infoblox/resource_infoblox_ip.go: -------------------------------------------------------------------------------- 1 | package infoblox 2 | 3 | /* 4 | This resource interface is basically a "helper" for the most common use case 5 | when using Infoblox -- you want to allocate an IP address from a particular 6 | network, and you want to get the next available IP address to use in creating 7 | an A record. This resource will locate the network you want by CIDR (or other 8 | infoblox supported keys -- still specified as a "CIDR" in your terraform file), and 9 | then invoke NextAvailableIP against it, and return the result in a variable called 10 | "ipaddress". 11 | 12 | Note: this entire resource should probably be deprecated if someone 13 | implements a full Network resource (though the complexity of the 14 | API for such a resource might make it advisable to leave this 15 | around as a simple alternative for this common use case. 16 | 17 | 18 | Usage in Terraform file: 19 | 20 | 21 | provider "infoblox" { 22 | username="whazzup" 23 | password="nuttin" 24 | host="https://infoblox.mydomain.com" 25 | sslverify="false" 26 | usecookies="false" 27 | } 28 | 29 | #this is the resource exposed by resource_infoblox_ip.go 30 | #it will create a variable called "ipaddress" 31 | resource "infoblox_ip" "theIPAddress" { 32 | cidr = "10.0.0.0/24" 33 | } 34 | 35 | #notice how the requested IP address is passed from the previous resource 36 | #to this one through the "ipaddress" variable 37 | resource "infoblox_record" "foobar" { 38 | value = "${infoblox_ip.theIPAddress.ipaddress}" 39 | name = "terraform" 40 | domain = "mydomain.com" 41 | type = "A" 42 | ttl = 3600 43 | } 44 | 45 | 46 | */ 47 | 48 | import ( 49 | "fmt" 50 | "strings" 51 | 52 | "github.com/fanatic/go-infoblox" 53 | "github.com/hashicorp/terraform/helper/schema" 54 | ) 55 | 56 | func resourceInfobloxIP() *schema.Resource { 57 | return &schema.Resource{ 58 | Create: resourceInfobloxIPCreate, 59 | Read: resourceInfobloxIPRead, 60 | Update: resourceInfobloxIPUpdate, 61 | Delete: resourceInfobloxIPDelete, 62 | 63 | Schema: map[string]*schema.Schema{ 64 | "cidr": &schema.Schema{ 65 | Type: schema.TypeString, 66 | Optional: true, 67 | ForceNew: false, 68 | }, 69 | 70 | "ip_range": &schema.Schema{ 71 | Type: schema.TypeString, 72 | Optional: true, 73 | ForceNew: false, 74 | ConflictsWith: []string{"cidr"}, 75 | }, 76 | 77 | "ipaddress": &schema.Schema{ 78 | Type: schema.TypeString, 79 | Computed: true, 80 | Required: false, 81 | }, 82 | 83 | "exclude": &schema.Schema{ 84 | Type: schema.TypeSet, 85 | Elem: &schema.Schema{Type: schema.TypeString}, 86 | Optional: true, 87 | }, 88 | }, 89 | } 90 | } 91 | 92 | func resourceInfobloxIPCreate(d *schema.ResourceData, meta interface{}) error { 93 | if err := validateIPData(d); err != nil { 94 | return err 95 | } 96 | 97 | var ( 98 | result string 99 | err error 100 | ) 101 | 102 | client := meta.(*infoblox.Client) 103 | excludedAddresses := buildExcludedAddressesArray(d) 104 | 105 | if cidr, ok := d.GetOk("cidr"); ok { 106 | result, err = getNextAvailableIPFromCIDR(client, cidr.(string), excludedAddresses) 107 | } else if ipRange, ok := d.GetOk("ip_range"); ok { 108 | result, err = getNextAvailableIPFromRange(client, ipRange.(string)) 109 | } 110 | 111 | if err != nil { 112 | return err 113 | } 114 | 115 | d.SetId(result) 116 | d.Set("ipaddress", result) 117 | 118 | return nil 119 | } 120 | 121 | func getNextAvailableIPFromCIDR(client *infoblox.Client, cidr string, excludedAddresses []string) (string, error) { 122 | var ( 123 | result string 124 | err error 125 | ou map[string]interface{} 126 | ) 127 | 128 | network, err := getNetworks(client, cidr) 129 | 130 | if err != nil { 131 | if strings.Contains(err.Error(), "Authorization Required") { 132 | return "", fmt.Errorf("[ERROR] Authentication Error, Please check your username/password ") 133 | } 134 | } 135 | 136 | if len(network) == 0 { 137 | err = fmt.Errorf("[ERROR] Empty response from client.Network().find. Is %s a valid network?", cidr) 138 | } 139 | 140 | if err == nil { 141 | ou, err = client.NetworkObject(network[0]["_ref"].(string)).NextAvailableIP(1, excludedAddresses) 142 | result = getMapValueAsString(ou, "ips") 143 | if result == "" { 144 | err = fmt.Errorf("[ERROR] Unable to determine IP address from response") 145 | } 146 | } 147 | 148 | return result, err 149 | } 150 | 151 | func getNextAvailableIPFromRange(client *infoblox.Client, ipRange string) (string, error) { 152 | var ( 153 | result string 154 | err error 155 | ) 156 | 157 | ips := strings.Split(ipRange, "-") 158 | if len(ips) != 2 { 159 | return "", fmt.Errorf("[ERROR] ip_range must be of format -. Instead found: %s", ipRange) 160 | } 161 | 162 | ou, err := client.FindUnusedIPInRange(ips[0], ips[1]) 163 | result = ou[0].IPAddress 164 | 165 | return result, err 166 | } 167 | 168 | func resourceInfobloxIPRead(d *schema.ResourceData, meta interface{}) error { 169 | 170 | // since the infoblox network object's NextAvailableIP function isn't exactly 171 | // a resource (you don't really allocate an IP address until you use the record:a or 172 | // record:host object), we don't actually implement READ, UPDATE, or DELETE 173 | 174 | return nil 175 | } 176 | 177 | func resourceInfobloxIPUpdate(d *schema.ResourceData, meta interface{}) error { 178 | 179 | // since the infoblox network object's NextAvailableIP function isn't exactly 180 | // a resource (you don't really allocate an IP address until you use the record:a or 181 | // record:host object), we don't actually implement READ, UPDATE, or DELETE 182 | 183 | return nil 184 | } 185 | 186 | func resourceInfobloxIPDelete(d *schema.ResourceData, meta interface{}) error { 187 | 188 | // since the infoblox network object's NextAvailableIP function isn't exactly 189 | // a resource (you don't really allocate an IP address until you use the record:a or 190 | // record:host object), we don't actually implement READ, UPDATE, or DELETE 191 | 192 | return nil 193 | } 194 | -------------------------------------------------------------------------------- /infoblox/resource_infoblox_record_ptr.go: -------------------------------------------------------------------------------- 1 | package infoblox 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | 8 | infoblox "github.com/fanatic/go-infoblox" 9 | "github.com/hashicorp/terraform/helper/schema" 10 | ) 11 | 12 | func infobloxRecordPTR() *schema.Resource { 13 | return &schema.Resource{ 14 | Create: resourceInfobloxPTRRecordCreate, 15 | Read: resourceInfobloxPTRRecordRead, 16 | Update: resourceInfobloxPTRRecordUpdate, 17 | Delete: resourceInfobloxPTRRecordDelete, 18 | 19 | Schema: map[string]*schema.Schema{ 20 | "address": &schema.Schema{ 21 | Type: schema.TypeString, 22 | Optional: true, 23 | ForceNew: true, 24 | ConflictsWith: []string{"name"}, 25 | }, 26 | "ptrdname": &schema.Schema{ 27 | Type: schema.TypeString, 28 | Required: true, 29 | ForceNew: true, 30 | }, 31 | "name": &schema.Schema{ 32 | Type: schema.TypeString, 33 | Optional: true, 34 | ConflictsWith: []string{"address"}, 35 | }, 36 | "comment": &schema.Schema{ 37 | Type: schema.TypeString, 38 | Optional: true, 39 | Default: "", 40 | }, 41 | "ttl": &schema.Schema{ 42 | Type: schema.TypeInt, 43 | Optional: true, 44 | }, 45 | "view": &schema.Schema{ 46 | Type: schema.TypeString, 47 | Optional: true, 48 | }, 49 | }, 50 | } 51 | } 52 | 53 | func resourceInfobloxPTRRecordCreate(d *schema.ResourceData, meta interface{}) error { 54 | err := validatePTRFields(d) 55 | if err != nil { 56 | return err 57 | } 58 | 59 | client := meta.(*infoblox.Client) 60 | record := url.Values{} 61 | 62 | if attr, ok := d.GetOk("address"); ok { 63 | addressType, err := ipType(attr.(string)) 64 | if err != nil { 65 | return err 66 | } 67 | record.Add(addressType, attr.(string)) 68 | } else { 69 | record.Add("name", d.Get("name").(string)) 70 | } 71 | record.Add("ptrdname", d.Get("ptrdname").(string)) 72 | populateSharedAttributes(d, &record) 73 | 74 | log.Printf("[DEBUG] Creating Infoblox PTR record with configuration: %#v", record) 75 | 76 | opts := ptrOpts(d) 77 | recordID, err := client.RecordPtr().Create(record, opts, nil) 78 | 79 | if err != nil { 80 | return fmt.Errorf("error creating infoblox PTR record: %s", err.Error()) 81 | } 82 | 83 | d.SetId(recordID) 84 | log.Printf("[INFO] Infoblox PTR record created with ID: %s", d.Id()) 85 | 86 | return nil 87 | } 88 | 89 | func resourceInfobloxPTRRecordRead(d *schema.ResourceData, meta interface{}) error { 90 | client := meta.(*infoblox.Client) 91 | 92 | opts := ptrOpts(d) 93 | record, err := client.GetRecordPtr(d.Id(), opts) 94 | if err != nil { 95 | return handleReadError(d, "PTR", err) 96 | } 97 | 98 | d.Set("ptrdname", record.PtrDname) 99 | 100 | if &record.Ipv4Addr != nil { 101 | d.Set("address", record.Ipv4Addr) 102 | } 103 | if &record.Ipv6Addr != nil { 104 | d.Set("address", record.Ipv6Addr) 105 | } 106 | if &record.Name != nil { 107 | d.Set("name", record.Name) 108 | } 109 | if &record.Comment != nil { 110 | d.Set("comment", record.Comment) 111 | } 112 | if &record.Ttl != nil { 113 | d.Set("ttl", record.Ttl) 114 | } 115 | if &record.View != nil { 116 | d.Set("view", record.View) 117 | } 118 | 119 | return nil 120 | } 121 | 122 | func resourceInfobloxPTRRecordUpdate(d *schema.ResourceData, meta interface{}) error { 123 | client := meta.(*infoblox.Client) 124 | record := url.Values{} 125 | 126 | opts := ptrOpts(d) 127 | _, err := client.GetRecordPtr(d.Id(), opts) 128 | if err != nil { 129 | return fmt.Errorf("error finding infoblox PTR record: %s", err.Error()) 130 | } 131 | 132 | if attr, ok := d.GetOk("address"); ok { 133 | addressType, err := ipType(attr.(string)) 134 | if err != nil { 135 | return err 136 | } 137 | record.Add(addressType, attr.(string)) 138 | } else { 139 | record.Add("name", d.Get("name").(string)) 140 | } 141 | record.Add("ptrdname", d.Get("ptrdname").(string)) 142 | populateSharedAttributes(d, &record) 143 | 144 | log.Printf("[DEBUG] Updating Infoblox PTR record with configuration: %#v", record) 145 | 146 | recordID, err := client.RecordPtrObject(d.Id()).Update(record, opts, nil) 147 | if err != nil { 148 | return fmt.Errorf("error updating Infoblox PTR record: %s", err.Error()) 149 | } 150 | 151 | d.SetId(recordID) 152 | log.Printf("[INFO] Infoblox PTR record updated with ID: %s", d.Id()) 153 | 154 | return resourceInfobloxPTRRecordRead(d, meta) 155 | } 156 | 157 | func resourceInfobloxPTRRecordDelete(d *schema.ResourceData, meta interface{}) error { 158 | client := meta.(*infoblox.Client) 159 | 160 | log.Printf("[DEBUG] Deleting Infoblox PTR record: %s, %s", d.Get("ptrdname").(string), d.Id()) 161 | _, err := client.GetRecordPtr(d.Id(), nil) 162 | if err != nil { 163 | return fmt.Errorf("error finding Infoblox PTR record: %s", err.Error()) 164 | } 165 | 166 | err = client.RecordPtrObject(d.Id()).Delete(nil) 167 | if err != nil { 168 | return fmt.Errorf("error deleting Infoblox PTR record: %s", err.Error()) 169 | } 170 | 171 | return nil 172 | } 173 | 174 | // Returns an error if neither address and name are set or if both are set 175 | func validatePTRFields(d *schema.ResourceData) error { 176 | _, hasAddress := d.GetOk("address") 177 | _, hasName := d.GetOk("name") 178 | if hasAddress && hasName { 179 | return fmt.Errorf("you must specify name or address for PTR record, not both") 180 | } 181 | if !(hasAddress || hasName) { 182 | return fmt.Errorf("you must specify a name of an address for PTR record") 183 | } 184 | 185 | return nil 186 | } 187 | 188 | // A PTR object can have either an ipv4/ipv6 address or a name, so when 189 | // constructing our ReturnFields slice we read the Schema to see which we want 190 | // to return. 191 | func ptrOpts(d *schema.ResourceData) *infoblox.Options { 192 | opts := []string{"ptrdname", "ttl", "comment", "view"} 193 | 194 | if _, ok := d.GetOk("name"); ok { 195 | opts = append(opts, "name") 196 | } 197 | if _, ok := d.GetOk("ipv4addr"); ok { 198 | opts = append(opts, "ipv4addr") 199 | } 200 | if _, ok := d.GetOk("ipv6addr"); ok { 201 | opts = append(opts, "ipv6addr") 202 | } 203 | 204 | return &infoblox.Options{ReturnFields: opts} 205 | } 206 | -------------------------------------------------------------------------------- /infoblox/resource_infoblox_record.go: -------------------------------------------------------------------------------- 1 | package infoblox 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | "strings" 8 | 9 | "github.com/fanatic/go-infoblox" 10 | "github.com/hashicorp/terraform/helper/schema" 11 | ) 12 | 13 | var deprecated = `The entire 'infoblox_record' 14 | resource is deprecated and will no longer see active development. It is 15 | recommended you use the dedicated infoblox_record_* resources instead.` 16 | 17 | func resourceInfobloxRecord() *schema.Resource { 18 | return &schema.Resource{ 19 | Create: resourceInfobloxRecordCreate, 20 | Read: resourceInfobloxRecordRead, 21 | Update: resourceInfobloxRecordUpdate, 22 | Delete: resourceInfobloxRecordDelete, 23 | 24 | Schema: map[string]*schema.Schema{ 25 | "domain": &schema.Schema{ 26 | Type: schema.TypeString, 27 | Required: true, 28 | ForceNew: true, 29 | Deprecated: deprecated, 30 | }, 31 | 32 | "name": &schema.Schema{ 33 | Type: schema.TypeString, 34 | Required: true, 35 | }, 36 | 37 | "value": &schema.Schema{ 38 | Type: schema.TypeString, 39 | Required: true, 40 | }, 41 | 42 | "type": &schema.Schema{ 43 | Type: schema.TypeString, 44 | Required: true, 45 | }, 46 | 47 | "ttl": &schema.Schema{ 48 | Type: schema.TypeString, 49 | Optional: true, 50 | Default: "3600", 51 | }, 52 | 53 | "view": &schema.Schema{ 54 | Type: schema.TypeString, 55 | Optional: true, 56 | Default: "default", 57 | }, 58 | }, 59 | } 60 | } 61 | 62 | func resourceInfobloxRecordCreate(d *schema.ResourceData, meta interface{}) error { 63 | client := meta.(*infoblox.Client) 64 | 65 | record := url.Values{} 66 | if err := getAll(d, record); err != nil { 67 | return err 68 | } 69 | 70 | log.Printf("[DEBUG] Infoblox Record create configuration: %#v", record) 71 | 72 | var recID string 73 | var err error 74 | 75 | switch strings.ToUpper(d.Get("type").(string)) { 76 | case "A": 77 | opts := &infoblox.Options{ 78 | ReturnFields: []string{"ttl", "ipv4addr", "name", "view"}, 79 | } 80 | recID, err = client.RecordA().Create(record, opts, nil) 81 | case "AAAA": 82 | opts := &infoblox.Options{ 83 | ReturnFields: []string{"ttl", "ipv6addr", "name", "view"}, 84 | } 85 | recID, err = client.RecordAAAA().Create(record, opts, nil) 86 | case "CNAME": 87 | opts := &infoblox.Options{ 88 | ReturnFields: []string{"ttl", "canonical", "name", "view"}, 89 | } 90 | recID, err = client.RecordCname().Create(record, opts, nil) 91 | default: 92 | return fmt.Errorf("resourceInfobloxRecordCreate: unknown type") 93 | } 94 | 95 | if err != nil { 96 | return fmt.Errorf("Failed to create Infoblox Record: %s", err.Error()) 97 | } 98 | 99 | d.SetId(recID) 100 | log.Printf("[INFO] record ID: %s", d.Id()) 101 | 102 | return resourceInfobloxRecordRead(d, meta) 103 | } 104 | 105 | func resourceInfobloxRecordRead(d *schema.ResourceData, meta interface{}) error { 106 | client := meta.(*infoblox.Client) 107 | 108 | switch strings.ToUpper(d.Get("type").(string)) { 109 | case "A": 110 | rec, err := client.GetRecordA(d.Id(), nil) 111 | if err != nil { 112 | return handleReadError(d, "A", err) 113 | } 114 | 115 | d.Set("value", rec.Ipv4Addr) 116 | d.Set("type", "A") 117 | fqdn := strings.Split(rec.Name, ".") 118 | d.Set("name", fqdn[0]) 119 | d.Set("domain", strings.Join(fqdn[1:], ".")) 120 | d.Set("ttl", rec.Ttl) 121 | d.Set("view", rec.View) 122 | 123 | case "AAAA": 124 | rec, err := client.GetRecordAAAA(d.Id(), nil) 125 | if err != nil { 126 | return handleReadError(d, "AAAA", err) 127 | } 128 | d.Set("value", rec.Ipv6Addr) 129 | d.Set("type", "AAAA") 130 | fqdn := strings.Split(rec.Name, ".") 131 | d.Set("name", fqdn[0]) 132 | d.Set("domain", strings.Join(fqdn[1:], ".")) 133 | d.Set("ttl", rec.Ttl) 134 | d.Set("view", rec.View) 135 | 136 | case "CNAME": 137 | rec, err := client.GetRecordCname(d.Id(), nil) 138 | if err != nil { 139 | return handleReadError(d, "CNAME", err) 140 | } 141 | d.Set("value", rec.Canonical) 142 | d.Set("type", "CNAME") 143 | fqdn := strings.Split(rec.Name, ".") 144 | d.Set("name", fqdn[0]) 145 | d.Set("domain", strings.Join(fqdn[1:], ".")) 146 | d.Set("ttl", rec.Ttl) 147 | d.Set("view", rec.View) 148 | default: 149 | return fmt.Errorf("resourceInfobloxRecordRead: unknown type") 150 | } 151 | 152 | return nil 153 | } 154 | 155 | func resourceInfobloxRecordUpdate(d *schema.ResourceData, meta interface{}) error { 156 | client := meta.(*infoblox.Client) 157 | var recID string 158 | var err, updateErr error 159 | switch strings.ToUpper(d.Get("type").(string)) { 160 | case "A": 161 | _, err = client.GetRecordA(d.Id(), nil) 162 | case "AAAA": 163 | _, err = client.GetRecordAAAA(d.Id(), nil) 164 | case "CNAME": 165 | _, err = client.GetRecordCname(d.Id(), nil) 166 | default: 167 | return fmt.Errorf("resourceInfobloxRecordUpdate: unknown type") 168 | } 169 | 170 | if err != nil { 171 | return fmt.Errorf("Couldn't find Infoblox record: %s", err) 172 | } 173 | 174 | record := url.Values{} 175 | if err := getAll(d, record); err != nil { 176 | return err 177 | } 178 | 179 | log.Printf("[DEBUG] Infoblox Record update configuration: %#v", record) 180 | 181 | switch strings.ToUpper(d.Get("type").(string)) { 182 | case "A": 183 | opts := &infoblox.Options{ 184 | ReturnFields: []string{"ttl", "ipv4addr", "name", "view"}, 185 | } 186 | recID, updateErr = client.RecordAObject(d.Id()).Update(record, opts, nil) 187 | case "AAAA": 188 | opts := &infoblox.Options{ 189 | ReturnFields: []string{"ttl", "ipv6addr", "name"}, 190 | } 191 | recID, updateErr = client.RecordAAAAObject(d.Id()).Update(record, opts, nil) 192 | case "CNAME": 193 | opts := &infoblox.Options{ 194 | ReturnFields: []string{"ttl", "canonical", "name"}, 195 | } 196 | recID, updateErr = client.RecordCnameObject(d.Id()).Update(record, opts, nil) 197 | default: 198 | return fmt.Errorf("resourceInfobloxRecordUpdate: unknown type") 199 | } 200 | 201 | if updateErr != nil { 202 | return fmt.Errorf("Failed to update Infoblox Record: %s", err.Error()) 203 | } 204 | 205 | d.SetId(recID) 206 | 207 | return resourceInfobloxRecordRead(d, meta) 208 | } 209 | 210 | func resourceInfobloxRecordDelete(d *schema.ResourceData, meta interface{}) error { 211 | client := meta.(*infoblox.Client) 212 | 213 | log.Printf("[INFO] Deleting Infoblox Record: %s, %s", d.Get("name").(string), d.Id()) 214 | switch strings.ToUpper(d.Get("type").(string)) { 215 | case "A": 216 | _, err := client.GetRecordA(d.Id(), nil) 217 | if err != nil { 218 | return fmt.Errorf("Couldn't find Infoblox A record: %s", err) 219 | } 220 | 221 | deleteErr := client.RecordAObject(d.Id()).Delete(nil) 222 | if deleteErr != nil { 223 | return fmt.Errorf("Error deleting Infoblox A Record: %s", deleteErr) 224 | } 225 | case "AAAA": 226 | _, err := client.GetRecordAAAA(d.Id(), nil) 227 | if err != nil { 228 | return fmt.Errorf("Couldn't find Infoblox AAAA record: %s", err) 229 | } 230 | 231 | deleteErr := client.RecordAAAAObject(d.Id()).Delete(nil) 232 | if deleteErr != nil { 233 | return fmt.Errorf("Error deleting Infoblox AAAA Record: %s", deleteErr) 234 | } 235 | case "CNAME": 236 | _, err := client.GetRecordCname(d.Id(), nil) 237 | if err != nil { 238 | return fmt.Errorf("Couldn't find Infoblox CNAME record: %s", err) 239 | } 240 | 241 | deleteErr := client.RecordCnameObject(d.Id()).Delete(nil) 242 | if deleteErr != nil { 243 | return fmt.Errorf("Error deleting Infoblox CNAME Record: %s", deleteErr) 244 | } 245 | default: 246 | return fmt.Errorf("resourceInfobloxRecordDelete: unknown type") 247 | } 248 | return nil 249 | } 250 | 251 | func getAll(d *schema.ResourceData, record url.Values) error { 252 | if attr, ok := d.GetOk("name"); ok { 253 | record.Set("name", attr.(string)) 254 | } 255 | 256 | if attr, ok := d.GetOk("domain"); ok { 257 | record.Set("name", strings.Join([]string{record.Get("name"), attr.(string)}, ".")) 258 | } 259 | 260 | if attr, ok := d.GetOk("ttl"); ok { 261 | record.Set("ttl", attr.(string)) 262 | } 263 | 264 | if attr, ok := d.GetOk("view"); ok { 265 | record.Set("view", attr.(string)) 266 | } 267 | 268 | var value string 269 | if attr, ok := d.GetOk("value"); ok { 270 | value = attr.(string) 271 | } 272 | 273 | switch strings.ToUpper(d.Get("type").(string)) { 274 | case "A": 275 | record.Set("ipv4addr", value) 276 | case "AAAA": 277 | record.Set("ipv6addr", value) 278 | case "CNAME": 279 | record.Set("canonical", value) 280 | default: 281 | return fmt.Errorf("getAll: type not found") 282 | } 283 | 284 | return nil 285 | } 286 | -------------------------------------------------------------------------------- /infoblox/resource_infoblox_record_host.go: -------------------------------------------------------------------------------- 1 | package infoblox 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | 8 | infoblox "github.com/fanatic/go-infoblox" 9 | "github.com/hashicorp/terraform/helper/schema" 10 | ) 11 | 12 | // hostIPv4Schema represents the schema for the host IPv4 sub-resource 13 | func hostIPv4Schema() map[string]*schema.Schema { 14 | return map[string]*schema.Schema{ 15 | "address": { 16 | Type: schema.TypeString, 17 | Required: true, 18 | }, 19 | "configure_for_dhcp": { 20 | Type: schema.TypeBool, 21 | Optional: true, 22 | }, 23 | "mac": { 24 | Type: schema.TypeString, 25 | Optional: true, 26 | }, 27 | } 28 | } 29 | 30 | // hostIPv6Schema represents the schema for the host IPv4 sub-resource 31 | func hostIPv6Schema() map[string]*schema.Schema { 32 | return map[string]*schema.Schema{ 33 | "address": { 34 | Type: schema.TypeString, 35 | Required: true, 36 | }, 37 | "configure_for_dhcp": { 38 | Type: schema.TypeBool, 39 | Optional: true, 40 | }, 41 | "mac": { 42 | Type: schema.TypeString, 43 | Optional: true, 44 | }, 45 | } 46 | } 47 | 48 | func infobloxRecordHost() *schema.Resource { 49 | return &schema.Resource{ 50 | Create: resourceInfobloxHostRecordCreate, 51 | Read: resourceInfobloxHostRecordRead, 52 | Update: resourceInfobloxHostRecordUpdate, 53 | Delete: resourceInfobloxHostRecordDelete, 54 | 55 | Schema: map[string]*schema.Schema{ 56 | "name": &schema.Schema{ 57 | Type: schema.TypeString, 58 | Required: true, 59 | ForceNew: true, 60 | }, 61 | "ipv4addr": &schema.Schema{ 62 | Type: schema.TypeList, 63 | Optional: true, 64 | Elem: &schema.Resource{Schema: hostIPv4Schema()}, 65 | }, 66 | "ipv6addr": &schema.Schema{ 67 | Type: schema.TypeList, 68 | Optional: true, 69 | Elem: &schema.Resource{Schema: hostIPv6Schema()}, 70 | }, 71 | "configure_for_dns": &schema.Schema{ 72 | Type: schema.TypeBool, 73 | Optional: true, 74 | Default: true, 75 | }, 76 | "comment": &schema.Schema{ 77 | Type: schema.TypeString, 78 | Optional: true, 79 | Default: "", 80 | }, 81 | "ttl": &schema.Schema{ 82 | Type: schema.TypeInt, 83 | Optional: true, 84 | }, 85 | "view": &schema.Schema{ 86 | Type: schema.TypeString, 87 | Optional: true, 88 | Default: "default", 89 | }, 90 | }, 91 | } 92 | } 93 | 94 | func ipv4sFromList(ipv4s []interface{}) []infoblox.HostIpv4Addr { 95 | var result []infoblox.HostIpv4Addr 96 | 97 | for _, v := range ipv4s { 98 | ipMap := v.(map[string]interface{}) 99 | i := infoblox.HostIpv4Addr{} 100 | 101 | i.Ipv4Addr = ipMap["address"].(string) 102 | 103 | if val, ok := ipMap["configure_for_dhcp"]; ok { 104 | i.ConfigureForDHCP = val.(bool) 105 | } 106 | if val, ok := ipMap["mac"]; ok { 107 | i.MAC = val.(string) 108 | } 109 | 110 | result = append(result, i) 111 | } 112 | return result 113 | } 114 | 115 | func ipv6sFromList(ipv6s []interface{}) []infoblox.HostIpv6Addr { 116 | var result []infoblox.HostIpv6Addr 117 | 118 | for _, v := range ipv6s { 119 | ipMap := v.(map[string]interface{}) 120 | i := infoblox.HostIpv6Addr{} 121 | 122 | i.Ipv6Addr = ipMap["address"].(string) 123 | 124 | if val, ok := ipMap["configure_for_dhcp"]; ok { 125 | i.ConfigureForDHCP = val.(bool) 126 | } 127 | if val, ok := ipMap["mac"]; ok { 128 | i.MAC = val.(string) 129 | } 130 | result = append(result, i) 131 | } 132 | return result 133 | } 134 | 135 | func hostObjectFromAttributes(d *schema.ResourceData) infoblox.RecordHostObject { 136 | hostObject := infoblox.RecordHostObject{} 137 | 138 | if attr, ok := d.GetOk("name"); ok { 139 | hostObject.Name = attr.(string) 140 | } 141 | if attr, ok := d.GetOk("configure_for_dns"); ok { 142 | hostObject.ConfigureForDNS = attr.(bool) 143 | } 144 | if attr, ok := d.GetOk("comment"); ok { 145 | hostObject.Comment = attr.(string) 146 | } 147 | if attr, ok := d.GetOk("ttl"); ok { 148 | hostObject.Ttl = attr.(int) 149 | } 150 | if attr, ok := d.GetOk("view"); ok { 151 | hostObject.View = attr.(string) 152 | } 153 | if attr, ok := d.GetOk("ipv4addr"); ok { 154 | hostObject.Ipv4Addrs = ipv4sFromList(attr.([]interface{})) 155 | } 156 | if attr, ok := d.GetOk("ipv6addr"); ok { 157 | hostObject.Ipv6Addrs = ipv6sFromList(attr.([]interface{})) 158 | } 159 | 160 | return hostObject 161 | } 162 | 163 | func resourceInfobloxHostRecordCreate(d *schema.ResourceData, meta interface{}) error { 164 | client := meta.(*infoblox.Client) 165 | 166 | record := url.Values{} 167 | hostObject := hostObjectFromAttributes(d) 168 | 169 | log.Printf("[DEBUG] Creating Infoblox Host record with configuration: %#v", hostObject) 170 | opts := &infoblox.Options{ 171 | ReturnFields: []string{"name", "ipv4addr", "ipv6addr", "configure_for_dns", "comment", "ttl", "view"}, 172 | } 173 | recordID, err := client.RecordHost().Create(record, opts, hostObject) 174 | if err != nil { 175 | return fmt.Errorf("error creating infoblox Host record: %s", err.Error()) 176 | } 177 | 178 | d.SetId(recordID) 179 | log.Printf("[INFO] Infoblox Host record created with ID: %s", d.Id()) 180 | 181 | return resourceInfobloxHostRecordRead(d, meta) 182 | } 183 | 184 | func resourceInfobloxHostRecordRead(d *schema.ResourceData, meta interface{}) error { 185 | client := meta.(*infoblox.Client) 186 | 187 | opts := &infoblox.Options{ 188 | ReturnFields: []string{"name", "ipv4addrs", "ipv6addrs", "configure_for_dns", "comment", "ttl", "view"}, 189 | } 190 | record, err := client.GetRecordHost(d.Id(), opts) 191 | if err != nil { 192 | return handleReadError(d, "Host", err) 193 | } 194 | 195 | d.Set("name", record.Name) 196 | 197 | if &record.ConfigureForDNS != nil { 198 | d.Set("configure_for_dns", record.ConfigureForDNS) 199 | } 200 | 201 | if &record.Comment != nil { 202 | d.Set("comment", record.Comment) 203 | } 204 | 205 | if &record.Ttl != nil { 206 | d.Set("ttl", record.Ttl) 207 | } 208 | 209 | if &record.View != nil { 210 | d.Set("view", record.View) 211 | } else { 212 | d.Set("view", "default") 213 | } 214 | 215 | if &record.Ipv4Addrs != nil { 216 | var result []interface{} 217 | 218 | for _, v := range record.Ipv4Addrs { 219 | i := make(map[string]interface{}) 220 | 221 | i["address"] = v.Ipv4Addr 222 | if &v.ConfigureForDHCP != nil { 223 | i["configure_for_dhcp"] = v.ConfigureForDHCP 224 | } 225 | if &v.MAC != nil { 226 | i["mac"] = v.MAC 227 | } 228 | 229 | result = append(result, i) 230 | } 231 | 232 | d.Set("ipv4addr", result) 233 | } 234 | if &record.Ipv6Addrs != nil { 235 | var result []interface{} 236 | 237 | for _, v := range record.Ipv6Addrs { 238 | i := make(map[string]interface{}) 239 | 240 | i["address"] = v.Ipv6Addr 241 | if &v.ConfigureForDHCP != nil { 242 | i["configure_for_dhcp"] = v.ConfigureForDHCP 243 | } 244 | if &v.MAC != nil { 245 | i["mac"] = v.MAC 246 | } 247 | 248 | result = append(result, i) 249 | } 250 | d.Set("ipv6addr", result) 251 | } 252 | 253 | return nil 254 | } 255 | 256 | func resourceInfobloxHostRecordUpdate(d *schema.ResourceData, meta interface{}) error { 257 | client := meta.(*infoblox.Client) 258 | 259 | opts := &infoblox.Options{ 260 | ReturnFields: []string{"name", "ipv4addrs", "ipv6addrs", "configure_for_dns", "comment", "ttl", "view"}, 261 | } 262 | _, err := client.GetRecordHost(d.Id(), opts) 263 | if err != nil { 264 | return fmt.Errorf("error finding infoblox Host record: %s", err.Error()) 265 | } 266 | 267 | record := url.Values{} 268 | hostObject := hostObjectFromAttributes(d) 269 | 270 | log.Printf("[DEBUG] Updating Infoblox Host record with configuration: %#v", hostObject) 271 | 272 | recordID, err := client.RecordHostObject(d.Id()).Update(record, opts, hostObject) 273 | if err != nil { 274 | return fmt.Errorf("error updating Infoblox Host record: %s", err.Error()) 275 | } 276 | 277 | d.SetId(recordID) 278 | log.Printf("[INFO] Infoblox Host record updated with ID: %s", d.Id()) 279 | 280 | return resourceInfobloxHostRecordRead(d, meta) 281 | } 282 | 283 | func resourceInfobloxHostRecordDelete(d *schema.ResourceData, meta interface{}) error { 284 | client := meta.(*infoblox.Client) 285 | 286 | log.Printf("[DEBUG] Deleting Infoblox Host record: %s, %s", d.Get("name").(string), d.Id()) 287 | _, err := client.GetRecordHost(d.Id(), nil) 288 | if err != nil { 289 | return fmt.Errorf("error finding Infoblox Host record: %s", err.Error()) 290 | } 291 | 292 | err = client.RecordHostObject(d.Id()).Delete(nil) 293 | if err != nil { 294 | return fmt.Errorf("error deleting Infoblox Host record: %s", err.Error()) 295 | } 296 | 297 | return nil 298 | } 299 | -------------------------------------------------------------------------------- /infoblox/resource_infoblox_record_test.go: -------------------------------------------------------------------------------- 1 | package infoblox 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | "testing" 8 | 9 | "github.com/fanatic/go-infoblox" 10 | "github.com/hashicorp/terraform/helper/resource" 11 | "github.com/hashicorp/terraform/terraform" 12 | ) 13 | 14 | func TestAccInfobloxRecord_Basic(t *testing.T) { 15 | var record infoblox.RecordAObject 16 | domain := os.Getenv("INFOBLOX_DOMAIN") 17 | 18 | resource.Test(t, resource.TestCase{ 19 | PreCheck: func() { testAccPreCheck(t) }, 20 | Providers: testAccProviders, 21 | CheckDestroy: testAccCheckInfobloxRecordDestroy, 22 | Steps: []resource.TestStep{ 23 | resource.TestStep{ 24 | Config: fmt.Sprintf(testInfobloxRecordConfigA, domain), 25 | Check: resource.ComposeTestCheckFunc( 26 | testAccCheckInfobloxRecordAExists("infoblox_record.test", &record), 27 | resource.TestCheckResourceAttr( 28 | "infoblox_record.test", "name", "testa"), 29 | resource.TestCheckResourceAttr( 30 | "infoblox_record.test", "domain", domain), 31 | resource.TestCheckResourceAttr( 32 | "infoblox_record.test", "type", "A"), 33 | resource.TestCheckResourceAttr( 34 | "infoblox_record.test", "value", "10.1.1.43"), 35 | resource.TestCheckResourceAttr( 36 | "infoblox_record.test", "ttl", "600"), 37 | ), 38 | }, 39 | }, 40 | }) 41 | } 42 | 43 | func TestAccInfobloxRecord_Updated(t *testing.T) { 44 | var record infoblox.RecordAObject 45 | domain := os.Getenv("INFOBLOX_DOMAIN") 46 | 47 | resource.Test(t, resource.TestCase{ 48 | PreCheck: func() { testAccPreCheck(t) }, 49 | Providers: testAccProviders, 50 | CheckDestroy: testAccCheckInfobloxRecordDestroy, 51 | Steps: []resource.TestStep{ 52 | resource.TestStep{ 53 | Config: fmt.Sprintf(testInfobloxRecordConfigA, domain), 54 | Check: resource.ComposeTestCheckFunc( 55 | testAccCheckInfobloxRecordAExists("infoblox_record.test", &record), 56 | resource.TestCheckResourceAttr( 57 | "infoblox_record.test", "name", "testa"), 58 | resource.TestCheckResourceAttr( 59 | "infoblox_record.test", "domain", domain), 60 | resource.TestCheckResourceAttr( 61 | "infoblox_record.test", "type", "A"), 62 | resource.TestCheckResourceAttr( 63 | "infoblox_record.test", "value", "10.1.1.43"), 64 | resource.TestCheckResourceAttr( 65 | "infoblox_record.test", "ttl", "600"), 66 | ), 67 | }, 68 | resource.TestStep{ 69 | Config: fmt.Sprintf(testInfobloxRecordConfigANew, domain), 70 | Check: resource.ComposeTestCheckFunc( 71 | testAccCheckInfobloxRecordAExists("infoblox_record.test", &record), 72 | resource.TestCheckResourceAttr( 73 | "infoblox_record.test", "name", "testa"), 74 | resource.TestCheckResourceAttr( 75 | "infoblox_record.test", "domain", domain), 76 | resource.TestCheckResourceAttr( 77 | "infoblox_record.test", "type", "A"), 78 | resource.TestCheckResourceAttr( 79 | "infoblox_record.test", "value", "10.1.1.50"), 80 | resource.TestCheckResourceAttr( 81 | "infoblox_record.test", "ttl", "600"), 82 | ), 83 | }, 84 | }, 85 | }) 86 | } 87 | 88 | func TestAccInfobloxRecordAAAA(t *testing.T) { 89 | var record infoblox.RecordAAAAObject 90 | domain := os.Getenv("INFOBLOX_DOMAIN") 91 | 92 | resource.Test(t, resource.TestCase{ 93 | PreCheck: func() { testAccPreCheck(t) }, 94 | Providers: testAccProviders, 95 | CheckDestroy: testAccCheckInfobloxRecordDestroy, 96 | Steps: []resource.TestStep{ 97 | resource.TestStep{ 98 | Config: fmt.Sprintf(testInfobloxRecordConfigAAAA, domain), 99 | Check: resource.ComposeTestCheckFunc( 100 | testAccCheckInfobloxRecordAAAAExists("infoblox_record.test", &record), 101 | resource.TestCheckResourceAttr( 102 | "infoblox_record.test", "name", "testaaaa"), 103 | resource.TestCheckResourceAttr( 104 | "infoblox_record.test", "domain", domain), 105 | resource.TestCheckResourceAttr( 106 | "infoblox_record.test", "type", "AAAA"), 107 | resource.TestCheckResourceAttr( 108 | "infoblox_record.test", "value", "fe80::c634:6bff:fe73:da10"), 109 | resource.TestCheckResourceAttr( 110 | "infoblox_record.test", "ttl", "600"), 111 | ), 112 | }, 113 | }, 114 | }) 115 | } 116 | 117 | func TestAccInfobloxRecordCname(t *testing.T) { 118 | var record infoblox.RecordCnameObject 119 | domain := os.Getenv("INFOBLOX_DOMAIN") 120 | 121 | resource.Test(t, resource.TestCase{ 122 | PreCheck: func() { testAccPreCheck(t) }, 123 | Providers: testAccProviders, 124 | CheckDestroy: testAccCheckInfobloxRecordDestroy, 125 | Steps: []resource.TestStep{ 126 | resource.TestStep{ 127 | Config: fmt.Sprintf(testInfobloxRecordConfigCname, domain), 128 | Check: resource.ComposeTestCheckFunc( 129 | testAccCheckInfobloxRecordCnameExists("infoblox_record.test", &record), 130 | resource.TestCheckResourceAttr( 131 | "infoblox_record.test", "name", "testcnamealias"), 132 | resource.TestCheckResourceAttr( 133 | "infoblox_record.test", "domain", domain), 134 | resource.TestCheckResourceAttr( 135 | "infoblox_record.test", "type", "CNAME"), 136 | resource.TestCheckResourceAttr( 137 | "infoblox_record.test", "value", "testcname"), 138 | resource.TestCheckResourceAttr( 139 | "infoblox_record.test", "ttl", "600"), 140 | ), 141 | }, 142 | }, 143 | }) 144 | } 145 | 146 | func testAccCheckInfobloxRecordDestroy(s *terraform.State) error { 147 | client := testAccProvider.Meta().(*infoblox.Client) 148 | 149 | for _, rs := range s.RootModule().Resources { 150 | if rs.Type != "infoblox_record" { 151 | continue 152 | } 153 | var err error 154 | 155 | switch strings.ToUpper(rs.Primary.Attributes["type"]) { 156 | case "A": 157 | _, err = client.GetRecordA(rs.Primary.ID, nil) 158 | case "AAAA": 159 | _, err = client.GetRecordAAAA(rs.Primary.ID, nil) 160 | case "CNAME": 161 | _, err = client.GetRecordCname(rs.Primary.ID, nil) 162 | default: 163 | return fmt.Errorf("testAccCheckInfobloxRecordDestroy: unknown type") 164 | } 165 | 166 | if err == nil { 167 | return fmt.Errorf("Record still exists") 168 | } 169 | } 170 | 171 | return nil 172 | } 173 | 174 | func testAccCheckInfobloxRecordAExists(n string, record *infoblox.RecordAObject) resource.TestCheckFunc { 175 | return func(s *terraform.State) error { 176 | rs, ok := s.RootModule().Resources[n] 177 | 178 | if !ok { 179 | return fmt.Errorf("Not found: %s", n) 180 | } 181 | 182 | if rs.Primary.ID == "" { 183 | return fmt.Errorf("No Record ID is set") 184 | } 185 | 186 | client := testAccProvider.Meta().(*infoblox.Client) 187 | foundRecord, err := client.GetRecordA(rs.Primary.ID, nil) 188 | 189 | if err != nil { 190 | return err 191 | } 192 | 193 | if foundRecord.Ref != rs.Primary.ID { 194 | return fmt.Errorf("Record not found") 195 | } 196 | 197 | *record = *foundRecord 198 | 199 | return nil 200 | } 201 | } 202 | 203 | func testAccCheckInfobloxRecordAAAAExists(n string, record *infoblox.RecordAAAAObject) resource.TestCheckFunc { 204 | return func(s *terraform.State) error { 205 | rs, ok := s.RootModule().Resources[n] 206 | 207 | if !ok { 208 | return fmt.Errorf("Not found: %s", n) 209 | } 210 | 211 | if rs.Primary.ID == "" { 212 | return fmt.Errorf("No Record ID is set") 213 | } 214 | 215 | client := testAccProvider.Meta().(*infoblox.Client) 216 | foundRecord, err := client.GetRecordAAAA(rs.Primary.ID, nil) 217 | 218 | if err != nil { 219 | return err 220 | } 221 | 222 | if foundRecord.Ref != rs.Primary.ID { 223 | return fmt.Errorf("Record not found") 224 | } 225 | 226 | *record = *foundRecord 227 | 228 | return nil 229 | } 230 | } 231 | 232 | func testAccCheckInfobloxRecordCnameExists(n string, record *infoblox.RecordCnameObject) resource.TestCheckFunc { 233 | return func(s *terraform.State) error { 234 | rs, ok := s.RootModule().Resources[n] 235 | 236 | if !ok { 237 | return fmt.Errorf("Not found: %s", n) 238 | } 239 | 240 | if rs.Primary.ID == "" { 241 | return fmt.Errorf("No Record ID is set") 242 | } 243 | 244 | client := testAccProvider.Meta().(*infoblox.Client) 245 | foundRecord, err := client.GetRecordCname(rs.Primary.ID, nil) 246 | 247 | if err != nil { 248 | return err 249 | } 250 | 251 | if foundRecord.Ref != rs.Primary.ID { 252 | return fmt.Errorf("Record not found") 253 | } 254 | 255 | *record = *foundRecord 256 | 257 | return nil 258 | } 259 | } 260 | 261 | const testInfobloxRecordConfigA = ` 262 | resource "infoblox_record" "test" { 263 | domain = "%s" 264 | value = "10.1.1.43" 265 | name = "testa" 266 | type = "A" 267 | ttl = 600 268 | 269 | }` 270 | 271 | const testInfobloxRecordConfigANew = ` 272 | resource "infoblox_record" "test" { 273 | domain = "%s" 274 | value = "10.1.1.50" 275 | name = "testa" 276 | type = "A" 277 | ttl = 600 278 | 279 | }` 280 | 281 | const testInfobloxRecordConfigCname = ` 282 | resource "infoblox_record" "test" { 283 | domain = "%s" 284 | value = "testcname" 285 | name = "testcnamealias" 286 | type = "CNAME" 287 | ttl = 600 288 | 289 | }` 290 | 291 | const testInfobloxRecordConfigAAAA = ` 292 | resource "infoblox_record" "test" { 293 | domain = "%s" 294 | value = "fe80::c634:6bff:fe73:da10" 295 | name = "testaaaa" 296 | type = "AAAA" 297 | ttl = 600 298 | 299 | }` 300 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Terraform](https://github.com/hashicorp/terraform) Infoblox Provider 2 | 3 | [![Build 4 | status](https://travis-ci.org/prudhvitella/terraform-provider-infoblox.svg)](https://travis-ci.org/prudhvitella/terraform-provider-infoblox) 5 | 6 | The Infoblox provider is used to interact with the 7 | resources supported by Infoblox. The provider needs to be configured 8 | with the proper credentials before it can be used. 9 | 10 | ## Download 11 | 12 | Download builds for Darwin, Linux and Windows from the [releases page](https://github.com/prudhvitella/terraform-provider-infoblox/releases/). 13 | 14 | ## Example Usage 15 | 16 | ```hcl 17 | # Configure the Infoblox provider 18 | provider "infoblox" { 19 | username = "${var.infoblox_username}" 20 | password = "${var.infoblox_password}" 21 | host = "${var.infoblox_host}" 22 | sslverify = "${var.infoblox_sslverify}" 23 | usecookies = "${var.infoblox_usecookies}" 24 | } 25 | 26 | # Create a record 27 | resource "infoblox_record_a" "www" { 28 | ... 29 | } 30 | ``` 31 | 32 | ## Argument Reference 33 | 34 | The following arguments are supported: 35 | 36 | * `username` - (Required) The Infoblox username. It must be provided, but it can also be sourced from the `INFOBLOX_USERNAME` environment variable. 37 | * `password` - (Required) The password associated with the username. It must be provided, but it can also be sourced from the `INFOBLOX_PASSWORD` environment variable. 38 | * `host` - (Required) The base url for the Infoblox REST API, but it can also be sourced from the `INFOBLOX_HOST` environment variable. 39 | * `sslverify` - (Required) Enable ssl for the REST api, but it can also be sourced from the `INFOBLOX_SSLVERIFY` environment variable. 40 | * `usecookies` - (Optional) Use cookies to connect to the REST API, but it can also be sourced from the `INFOBLOX_USECOOKIES` environment variable 41 | 42 | # infoblox\_record\_host 43 | 44 | Provides an Infoblox Host record resource. 45 | 46 | ## Example Usage 47 | 48 | ```hcl 49 | resource "infoblox_record_host" "host" { 50 | name = "terraformhost.platform.test-aib.pri" 51 | configure_for_dns = false 52 | 53 | ipv4addr { 54 | address = "10.89.130.30" 55 | } 56 | 57 | ipv4addr { 58 | address = "10.89.130.31" 59 | configure_for_dhcp = true 60 | mac = "01-23-45-67-89-10" 61 | } 62 | } 63 | ``` 64 | 65 | ## Argument Reference 66 | 67 | * `name` - (Required) The name of the record 68 | * `ipv4addr` - (Required) An IPv4 address object. At least one `iv4addr` or `ipv6addr` must be specified. See [ipv4addr options](#Ipv4addr_options) below. 69 | * `ipv6addr` - (Required) An IPv6 address object. At least one `iv4addr` or `ipv6addr` must be specified. See [ipv6addr options](#Ipv6addr_options) below. 70 | * `configure_for_dns` - (Boolean, Optional) Specify whether DNS should be configured for the record; defaults to `false` 71 | * `comment` - (Optional) The comment for the record 72 | * `ttl` - (Integer, Optional) The TTL of the record 73 | * `view` - (Optional) The view of the record 74 | 75 | ### Ipv4 options 76 | 77 | * `address` - (Required) The IPv4 address of the object 78 | * `configure_for_dhcp` - (Boolean, Optional) Specifies whether the IPv4 address object should be configured for DHCP 79 | * `mac` - (Optional) The MAC address of the resource 80 | 81 | ### Ipv6 options 82 | 83 | * `address` - (Required) The IPv6 address of the object 84 | * `configure_for_dhcp` - (Boolean, Optional) Specifies whether the IPv4 address object should be configured for DHCP 85 | * `mac` - (Optional) The MAC address of the resource 86 | 87 | # infoblox\_record\_a 88 | 89 | Provides an Infoblox A record resource. 90 | 91 | ## Example Usage 92 | 93 | ```hcl 94 | resource "infoblox_record_a" "web" { 95 | address = "10.1.2.3" 96 | name = "some.fqdn.lan" 97 | 98 | comment = "ipv4 address for Acme web server" 99 | ttl = 3600 100 | view = "default" 101 | } 102 | ``` 103 | 104 | ## Argument Reference 105 | 106 | The following arguments are supported: 107 | 108 | * `address` - (Required) The IPv4 address of the record 109 | * `name` - (Required) The FQDN of the record 110 | * `comment` - (Optional) The comment for the record 111 | * `ttl` - (Integer, Optional) The TTL of the record 112 | * `view` - (Optional) The view of the record 113 | 114 | # infoblox\_record\_aaaa 115 | 116 | Provides an Infoblox AAAA record resource. 117 | 118 | ## Example Usage 119 | 120 | ```hcl 121 | resource "infoblox_record_aaaa" "web" { 122 | address = "2001:db8:85a3::8a2e:370:7334" 123 | name = "some.fqdn.lan" 124 | 125 | comment = "ipv6 address for Acme web server" 126 | ttl = 3600 127 | view = "default" 128 | } 129 | ``` 130 | 131 | ## Argument Reference 132 | 133 | The following arguments are supported: 134 | 135 | * `address` - (Required) The IPv6 address of the record 136 | * `name` - (Required) The FQDN of the record 137 | * `comment` - (Optional) The comment for the record 138 | * `ttl` - (Integer, Optional) The TTL of the record 139 | * `view` - (Optional) The view of the record 140 | 141 | # infoblox\_record\_cname 142 | 143 | Provides an Infoblox CNAME record resource. 144 | 145 | ## Example Usage 146 | 147 | ```hcl 148 | resource "infoblox_record_cname" "www" { 149 | canonical = "fqdn.lan" 150 | name = "www.fqdn.lan" 151 | 152 | comment = "ipv6 address for Acme web server" 153 | ttl = 3600 154 | view = "www.fqdn.lan is an alias for fqdn.lan" 155 | } 156 | ``` 157 | 158 | ## Argument Reference 159 | 160 | The following arguments are supported: 161 | 162 | * `canonical` - (Required) The canonical address to point to 163 | * `name` - (Required) The FQDN of the alias 164 | * `comment` - (Optional) The comment for the record 165 | * `ttl` - (Integer, Optional) The TTL of the record 166 | * `view` - (Optional) The view of the record 167 | 168 | # infoblox\_record\_ptr 169 | 170 | Provides an Infoblox PTR record resource. 171 | 172 | ## Example Usage 173 | 174 | ```hcl 175 | resource "infoblox_record_ptr" "ptr" { 176 | ptrdname = "some.fqdn.lan" 177 | address = "10.0.0.10.in-addr.arpa" 178 | 179 | comment = "Reverse lookup for some.fqdn.lan" 180 | ttl = 3600 181 | view = "default" 182 | } 183 | ``` 184 | 185 | ## Argument Reference 186 | 187 | The following arguments are supported: 188 | 189 | * `ptrdname` - (Required) The 190 | * `address` - (Required, conflicts with `name`) This field is required if you do not use the name field. Either the IP address or name is required. Example: 10.0.0.11. If the PTR record belongs to a forward-mapping zone, this field is empty. Accepts both IPv4 and IPv6 addresses. 191 | * `name` - (Required, conflicts with `address`) This field is required if you do not use the address field. Either the IP address or name is required. Example: 10.0.0.10.in.addr.arpa 192 | * `comment` - (Optional) The comment for the record 193 | * `ttl` - (Integer, Optional) The TTL of the record 194 | * `view` - (Optional) The view of the record 195 | 196 | # infoblox\_record\_txt 197 | 198 | Provides an Infoblox TXT record resource. 199 | 200 | ## Example Usage 201 | 202 | ```hcl 203 | resource "infoblox_record_txt" "txt" { 204 | name = "some.fqdn.lan" 205 | text = "Welcome to the Jungle" 206 | } 207 | ``` 208 | 209 | ## Argument Reference 210 | 211 | The following arguments are supported: 212 | 213 | * `name` - (Required) The name of the TXT record 214 | * `text` - (Required) The text of the TXT record 215 | * `comment` - (Optional) The comment for the record 216 | * `ttl` - (Integer, Optional) The TTL of the record 217 | * `view` - (Optional) The view of the record 218 | 219 | # infoblox\_record\_srv 220 | 221 | Provides an Infoblox SRV record resource. 222 | 223 | ## Example Usage 224 | 225 | ```hcl 226 | resource "infoblox_record_srv" "srv" { 227 | name = "bind_srv.domain.com" 228 | port = 1234 229 | priority = 1 230 | weight = 1 231 | target = "old.target.test.org" 232 | } 233 | ``` 234 | 235 | ## Argument Reference 236 | 237 | The following arguments are supported: 238 | 239 | * `name` - (Required) The name of the record 240 | * `port` - (Integer, Required) The port of the SRV record 241 | * `priority` - (Integer, Required) The priority of the SRV record 242 | * `weight` - (Integer, Required) The weight of the SRV record 243 | * `target` - (Required) The target of the SRV record 244 | * `comment` - (Optional) The comment for the record 245 | * `ttl` - (Integer, Optional) The TTL of the record 246 | * `view` - (Optional) The view of the record 247 | 248 | # infoblox\_ip 249 | 250 | Queries the next available IP address from a network and returns it in a computed variable 251 | that can be used by the infoblox_record resource. 252 | 253 | ## Example Usage 254 | 255 | ```hcl 256 | # Acquire the next available IP from a network CIDR 257 | # it will create a variable called "ipaddress" 258 | resource "infoblox_ip" "ip" { 259 | cidr = "10.0.0.0/24" 260 | } 261 | 262 | resource "infoblox_record_a" "web" { 263 | address = "${infoblox_ip.ip.ipaddress}" 264 | name = "some.fqdn.lan" 265 | 266 | comment = "ipv4 address for Acme web server" 267 | ttl = 3600 268 | view = "default" 269 | } 270 | 271 | # Exclude specific IP addresses when acquiring next 272 | # avaiable IP from a network CIDR 273 | resource "infoblox_ip" "excludedIPAddress" { 274 | cidr = "10.0.0.0/24" 275 | 276 | exclude = [ 277 | "10.0.0.1", 278 | "10.0.0.2" 279 | # etc. 280 | ] 281 | } 282 | 283 | # Acquire free IP address from within a specific 284 | # range of addresses 285 | resource "infoblox_ip" "ipAddressFromRange" { 286 | ip_range = "10.0.0.20-10.0.0.60" 287 | } 288 | ``` 289 | 290 | ## Argument Reference 291 | 292 | The following arguments are supported: 293 | 294 | * `cidr` - (Required) The network to search for - example 10.0.0.0/24. Cannot be specified with `ip_range` 295 | * `exclude` - (Optional) A list of IP addresses to exclude 296 | * `ip_range` - (Required) The IP range to search within - example 10.0.0.20-10.0.0.40. Cannot be 297 | specified with `cidr` 298 | 299 | # Deprecated Resources 300 | 301 | The following resources are deprecated and will no longer see active development. It is recommended you use the dedicated `infoblox_record_*` resources instead. 302 | 303 | ## infoblox\_record 304 | 305 | Provides a Infoblox record resource. 306 | 307 | ### Example Usage 308 | 309 | ```hcl 310 | # Add a record to the domain 311 | resource "infoblox_record" "foobar" { 312 | value = "192.168.0.10" 313 | name = "terraform" 314 | domain = "mydomain.com" 315 | type = "A" 316 | ttl = 3600 317 | } 318 | ``` 319 | 320 | ### Argument Reference 321 | 322 | See [related part of Infoblox Docs](https://godoc.org/github.com/fanatic/go-infoblox) for details about valid values. 323 | 324 | The following arguments are supported: 325 | 326 | * `domain` - (Required) The domain to add the record to 327 | * `value` - (Required) The value of the record; its usage will depend on the `type` (see below) 328 | * `name` - (Required) The name of the record 329 | * `ttl` - (Integer, Optional) The TTL of the record 330 | * `type` - (Required) The type of the record 331 | * `comment` - (Optional) The comment of the record 332 | 333 | ### DNS Record Types 334 | 335 | The type of record being created affects the interpretation of the `value` argument. 336 | 337 | #### A Record 338 | 339 | * `value` is the IPv4 address 340 | 341 | #### CNAME Record 342 | 343 | * `value` is the alias name 344 | 345 | #### AAAA Record 346 | 347 | * `value` is the IPv6 address 348 | 349 | ### Attributes Reference 350 | 351 | The following attributes are exported: 352 | 353 | * `domain` - The domain of the record 354 | * `value` - The value of the record 355 | * `name` - The name of the record 356 | * `type` - The type of the record 357 | * `ttl` - The TTL of the record 358 | 359 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License, version 2.0 2 | 3 | 1. Definitions 4 | 5 | 1.1. “Contributor” 6 | 7 | means each individual or legal entity that creates, contributes to the 8 | creation of, or owns Covered Software. 9 | 10 | 1.2. “Contributor Version” 11 | 12 | means the combination of the Contributions of others (if any) used by a 13 | Contributor and that particular Contributor’s Contribution. 14 | 15 | 1.3. “Contribution” 16 | 17 | means Covered Software of a particular Contributor. 18 | 19 | 1.4. “Covered Software” 20 | 21 | means Source Code Form to which the initial Contributor has attached the 22 | notice in Exhibit A, the Executable Form of such Source Code Form, and 23 | Modifications of such Source Code Form, in each case including portions 24 | thereof. 25 | 26 | 1.5. “Incompatible With Secondary Licenses” 27 | means 28 | 29 | a. that the initial Contributor has attached the notice described in 30 | Exhibit B to the Covered Software; or 31 | 32 | b. that the Covered Software was made available under the terms of version 33 | 1.1 or earlier of the License, but not also under the terms of a 34 | Secondary License. 35 | 36 | 1.6. “Executable Form” 37 | 38 | means any form of the work other than Source Code Form. 39 | 40 | 1.7. “Larger Work” 41 | 42 | means a work that combines Covered Software with other material, in a separate 43 | file or files, that is not Covered Software. 44 | 45 | 1.8. “License” 46 | 47 | means this document. 48 | 49 | 1.9. “Licensable” 50 | 51 | means having the right to grant, to the maximum extent possible, whether at the 52 | time of the initial grant or subsequently, any and all of the rights conveyed by 53 | this License. 54 | 55 | 1.10. “Modifications” 56 | 57 | means any of the following: 58 | 59 | a. any file in Source Code Form that results from an addition to, deletion 60 | from, or modification of the contents of Covered Software; or 61 | 62 | b. any new file in Source Code Form that contains any Covered Software. 63 | 64 | 1.11. “Patent Claims” of a Contributor 65 | 66 | means any patent claim(s), including without limitation, method, process, 67 | and apparatus claims, in any patent Licensable by such Contributor that 68 | would be infringed, but for the grant of the License, by the making, 69 | using, selling, offering for sale, having made, import, or transfer of 70 | either its Contributions or its Contributor Version. 71 | 72 | 1.12. “Secondary License” 73 | 74 | means either the GNU General Public License, Version 2.0, the GNU Lesser 75 | General Public License, Version 2.1, the GNU Affero General Public 76 | License, Version 3.0, or any later versions of those licenses. 77 | 78 | 1.13. “Source Code Form” 79 | 80 | means the form of the work preferred for making modifications. 81 | 82 | 1.14. “You” (or “Your”) 83 | 84 | means an individual or a legal entity exercising rights under this 85 | License. For legal entities, “You” includes any entity that controls, is 86 | controlled by, or is under common control with You. For purposes of this 87 | definition, “control” means (a) the power, direct or indirect, to cause 88 | the direction or management of such entity, whether by contract or 89 | otherwise, or (b) ownership of more than fifty percent (50%) of the 90 | outstanding shares or beneficial ownership of such entity. 91 | 92 | 93 | 2. License Grants and Conditions 94 | 95 | 2.1. Grants 96 | 97 | Each Contributor hereby grants You a world-wide, royalty-free, 98 | non-exclusive license: 99 | 100 | a. under intellectual property rights (other than patent or trademark) 101 | Licensable by such Contributor to use, reproduce, make available, 102 | modify, display, perform, distribute, and otherwise exploit its 103 | Contributions, either on an unmodified basis, with Modifications, or as 104 | part of a Larger Work; and 105 | 106 | b. under Patent Claims of such Contributor to make, use, sell, offer for 107 | sale, have made, import, and otherwise transfer either its Contributions 108 | or its Contributor Version. 109 | 110 | 2.2. Effective Date 111 | 112 | The licenses granted in Section 2.1 with respect to any Contribution become 113 | effective for each Contribution on the date the Contributor first distributes 114 | such Contribution. 115 | 116 | 2.3. Limitations on Grant Scope 117 | 118 | The licenses granted in this Section 2 are the only rights granted under this 119 | License. No additional rights or licenses will be implied from the distribution 120 | or licensing of Covered Software under this License. Notwithstanding Section 121 | 2.1(b) above, no patent license is granted by a Contributor: 122 | 123 | a. for any code that a Contributor has removed from Covered Software; or 124 | 125 | b. for infringements caused by: (i) Your and any other third party’s 126 | modifications of Covered Software, or (ii) the combination of its 127 | Contributions with other software (except as part of its Contributor 128 | Version); or 129 | 130 | c. under Patent Claims infringed by Covered Software in the absence of its 131 | Contributions. 132 | 133 | This License does not grant any rights in the trademarks, service marks, or 134 | logos of any Contributor (except as may be necessary to comply with the 135 | notice requirements in Section 3.4). 136 | 137 | 2.4. Subsequent Licenses 138 | 139 | No Contributor makes additional grants as a result of Your choice to 140 | distribute the Covered Software under a subsequent version of this License 141 | (see Section 10.2) or under the terms of a Secondary License (if permitted 142 | under the terms of Section 3.3). 143 | 144 | 2.5. Representation 145 | 146 | Each Contributor represents that the Contributor believes its Contributions 147 | are its original creation(s) or it has sufficient rights to grant the 148 | rights to its Contributions conveyed by this License. 149 | 150 | 2.6. Fair Use 151 | 152 | This License is not intended to limit any rights You have under applicable 153 | copyright doctrines of fair use, fair dealing, or other equivalents. 154 | 155 | 2.7. Conditions 156 | 157 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in 158 | Section 2.1. 159 | 160 | 161 | 3. Responsibilities 162 | 163 | 3.1. Distribution of Source Form 164 | 165 | All distribution of Covered Software in Source Code Form, including any 166 | Modifications that You create or to which You contribute, must be under the 167 | terms of this License. You must inform recipients that the Source Code Form 168 | of the Covered Software is governed by the terms of this License, and how 169 | they can obtain a copy of this License. You may not attempt to alter or 170 | restrict the recipients’ rights in the Source Code Form. 171 | 172 | 3.2. Distribution of Executable Form 173 | 174 | If You distribute Covered Software in Executable Form then: 175 | 176 | a. such Covered Software must also be made available in Source Code Form, 177 | as described in Section 3.1, and You must inform recipients of the 178 | Executable Form how they can obtain a copy of such Source Code Form by 179 | reasonable means in a timely manner, at a charge no more than the cost 180 | of distribution to the recipient; and 181 | 182 | b. You may distribute such Executable Form under the terms of this License, 183 | or sublicense it under different terms, provided that the license for 184 | the Executable Form does not attempt to limit or alter the recipients’ 185 | rights in the Source Code Form under this License. 186 | 187 | 3.3. Distribution of a Larger Work 188 | 189 | You may create and distribute a Larger Work under terms of Your choice, 190 | provided that You also comply with the requirements of this License for the 191 | Covered Software. If the Larger Work is a combination of Covered Software 192 | with a work governed by one or more Secondary Licenses, and the Covered 193 | Software is not Incompatible With Secondary Licenses, this License permits 194 | You to additionally distribute such Covered Software under the terms of 195 | such Secondary License(s), so that the recipient of the Larger Work may, at 196 | their option, further distribute the Covered Software under the terms of 197 | either this License or such Secondary License(s). 198 | 199 | 3.4. Notices 200 | 201 | You may not remove or alter the substance of any license notices (including 202 | copyright notices, patent notices, disclaimers of warranty, or limitations 203 | of liability) contained within the Source Code Form of the Covered 204 | Software, except that You may alter any license notices to the extent 205 | required to remedy known factual inaccuracies. 206 | 207 | 3.5. Application of Additional Terms 208 | 209 | You may choose to offer, and to charge a fee for, warranty, support, 210 | indemnity or liability obligations to one or more recipients of Covered 211 | Software. However, You may do so only on Your own behalf, and not on behalf 212 | of any Contributor. You must make it absolutely clear that any such 213 | warranty, support, indemnity, or liability obligation is offered by You 214 | alone, and You hereby agree to indemnify every Contributor for any 215 | liability incurred by such Contributor as a result of warranty, support, 216 | indemnity or liability terms You offer. You may include additional 217 | disclaimers of warranty and limitations of liability specific to any 218 | jurisdiction. 219 | 220 | 4. Inability to Comply Due to Statute or Regulation 221 | 222 | If it is impossible for You to comply with any of the terms of this License 223 | with respect to some or all of the Covered Software due to statute, judicial 224 | order, or regulation then You must: (a) comply with the terms of this License 225 | to the maximum extent possible; and (b) describe the limitations and the code 226 | they affect. Such description must be placed in a text file included with all 227 | distributions of the Covered Software under this License. Except to the 228 | extent prohibited by statute or regulation, such description must be 229 | sufficiently detailed for a recipient of ordinary skill to be able to 230 | understand it. 231 | 232 | 5. Termination 233 | 234 | 5.1. The rights granted under this License will terminate automatically if You 235 | fail to comply with any of its terms. However, if You become compliant, 236 | then the rights granted under this License from a particular Contributor 237 | are reinstated (a) provisionally, unless and until such Contributor 238 | explicitly and finally terminates Your grants, and (b) on an ongoing basis, 239 | if such Contributor fails to notify You of the non-compliance by some 240 | reasonable means prior to 60 days after You have come back into compliance. 241 | Moreover, Your grants from a particular Contributor are reinstated on an 242 | ongoing basis if such Contributor notifies You of the non-compliance by 243 | some reasonable means, this is the first time You have received notice of 244 | non-compliance with this License from such Contributor, and You become 245 | compliant prior to 30 days after Your receipt of the notice. 246 | 247 | 5.2. If You initiate litigation against any entity by asserting a patent 248 | infringement claim (excluding declaratory judgment actions, counter-claims, 249 | and cross-claims) alleging that a Contributor Version directly or 250 | indirectly infringes any patent, then the rights granted to You by any and 251 | all Contributors for the Covered Software under Section 2.1 of this License 252 | shall terminate. 253 | 254 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user 255 | license agreements (excluding distributors and resellers) which have been 256 | validly granted by You or Your distributors under this License prior to 257 | termination shall survive termination. 258 | 259 | 6. Disclaimer of Warranty 260 | 261 | Covered Software is provided under this License on an “as is” basis, without 262 | warranty of any kind, either expressed, implied, or statutory, including, 263 | without limitation, warranties that the Covered Software is free of defects, 264 | merchantable, fit for a particular purpose or non-infringing. The entire 265 | risk as to the quality and performance of the Covered Software is with You. 266 | Should any Covered Software prove defective in any respect, You (not any 267 | Contributor) assume the cost of any necessary servicing, repair, or 268 | correction. This disclaimer of warranty constitutes an essential part of this 269 | License. No use of any Covered Software is authorized under this License 270 | except under this disclaimer. 271 | 272 | 7. Limitation of Liability 273 | 274 | Under no circumstances and under no legal theory, whether tort (including 275 | negligence), contract, or otherwise, shall any Contributor, or anyone who 276 | distributes Covered Software as permitted above, be liable to You for any 277 | direct, indirect, special, incidental, or consequential damages of any 278 | character including, without limitation, damages for lost profits, loss of 279 | goodwill, work stoppage, computer failure or malfunction, or any and all 280 | other commercial damages or losses, even if such party shall have been 281 | informed of the possibility of such damages. This limitation of liability 282 | shall not apply to liability for death or personal injury resulting from such 283 | party’s negligence to the extent applicable law prohibits such limitation. 284 | Some jurisdictions do not allow the exclusion or limitation of incidental or 285 | consequential damages, so this exclusion and limitation may not apply to You. 286 | 287 | 8. Litigation 288 | 289 | Any litigation relating to this License may be brought only in the courts of 290 | a jurisdiction where the defendant maintains its principal place of business 291 | and such litigation shall be governed by laws of that jurisdiction, without 292 | reference to its conflict-of-law provisions. Nothing in this Section shall 293 | prevent a party’s ability to bring cross-claims or counter-claims. 294 | 295 | 9. Miscellaneous 296 | 297 | This License represents the complete agreement concerning the subject matter 298 | hereof. If any provision of this License is held to be unenforceable, such 299 | provision shall be reformed only to the extent necessary to make it 300 | enforceable. Any law or regulation which provides that the language of a 301 | contract shall be construed against the drafter shall not be used to construe 302 | this License against a Contributor. 303 | 304 | 305 | 10. Versions of the License 306 | 307 | 10.1. New Versions 308 | 309 | Mozilla Foundation is the license steward. Except as provided in Section 310 | 10.3, no one other than the license steward has the right to modify or 311 | publish new versions of this License. Each version will be given a 312 | distinguishing version number. 313 | 314 | 10.2. Effect of New Versions 315 | 316 | You may distribute the Covered Software under the terms of the version of 317 | the License under which You originally received the Covered Software, or 318 | under the terms of any subsequent version published by the license 319 | steward. 320 | 321 | 10.3. Modified Versions 322 | 323 | If you create software not governed by this License, and you want to 324 | create a new license for such software, you may create and use a modified 325 | version of this License if you rename the license and remove any 326 | references to the name of the license steward (except to note that such 327 | modified license differs from this License). 328 | 329 | 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses 330 | If You choose to distribute Source Code Form that is Incompatible With 331 | Secondary Licenses under the terms of this version of the License, the 332 | notice described in Exhibit B of this License must be attached. 333 | 334 | Exhibit A - Source Code Form License Notice 335 | 336 | This Source Code Form is subject to the 337 | terms of the Mozilla Public License, v. 338 | 2.0. If a copy of the MPL was not 339 | distributed with this file, You can 340 | obtain one at 341 | http://mozilla.org/MPL/2.0/. 342 | 343 | If it is not possible or desirable to put the notice in a particular file, then 344 | You may include the notice in a location (such as a LICENSE file in a relevant 345 | directory) where a recipient would be likely to look for such a notice. 346 | 347 | You may add additional accurate notices of copyright ownership. 348 | 349 | Exhibit B - “Incompatible With Secondary Licenses” Notice 350 | 351 | This Source Code Form is “Incompatible 352 | With Secondary Licenses”, as defined by 353 | the Mozilla Public License, v. 2.0. 354 | 355 | -------------------------------------------------------------------------------- /vendor/vendor.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "", 3 | "ignore": "test", 4 | "package": [ 5 | { 6 | "checksumSHA1": "7eAIWei337IlBYIfzA3HyOEV9WE=", 7 | "path": "github.com/apparentlymart/go-cidr/cidr", 8 | "revision": "2bd8b58cf4275aeb086ade613de226773e29e853", 9 | "revisionTime": "2017-06-16T19:18:03Z" 10 | }, 11 | { 12 | "checksumSHA1": "gNO0JNpLzYOdInGeq7HqMZUzx9M=", 13 | "origin": "github.com/hashicorp/terraform/vendor/github.com/armon/go-radix", 14 | "path": "github.com/armon/go-radix", 15 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 16 | "revisionTime": "2017-08-16T17:38:16Z" 17 | }, 18 | { 19 | "checksumSHA1": "DiiotYnD6Th+p18eN35GRZ8pr4c=", 20 | "path": "github.com/aws/aws-sdk-go/aws", 21 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 22 | "revisionTime": "2017-08-16T18:14:22Z" 23 | }, 24 | { 25 | "checksumSHA1": "Y9W+4GimK4Fuxq+vyIskVYFRnX4=", 26 | "path": "github.com/aws/aws-sdk-go/aws/awserr", 27 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 28 | "revisionTime": "2017-08-16T18:14:22Z" 29 | }, 30 | { 31 | "checksumSHA1": "yyYr41HZ1Aq0hWc3J5ijXwYEcac=", 32 | "path": "github.com/aws/aws-sdk-go/aws/awsutil", 33 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 34 | "revisionTime": "2017-08-16T18:14:22Z" 35 | }, 36 | { 37 | "checksumSHA1": "n98FANpNeRT5kf6pizdpI7nm6Sw=", 38 | "path": "github.com/aws/aws-sdk-go/aws/client", 39 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 40 | "revisionTime": "2017-08-16T18:14:22Z" 41 | }, 42 | { 43 | "checksumSHA1": "ieAJ+Cvp/PKv1LpUEnUXpc3OI6E=", 44 | "path": "github.com/aws/aws-sdk-go/aws/client/metadata", 45 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 46 | "revisionTime": "2017-08-16T18:14:22Z" 47 | }, 48 | { 49 | "checksumSHA1": "7/8j/q0TWtOgXyvEcv4B2Dhl00o=", 50 | "path": "github.com/aws/aws-sdk-go/aws/corehandlers", 51 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 52 | "revisionTime": "2017-08-16T18:14:22Z" 53 | }, 54 | { 55 | "checksumSHA1": "Y+cPwQL0dZMyqp3wI+KJWmA9KQ8=", 56 | "path": "github.com/aws/aws-sdk-go/aws/credentials", 57 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 58 | "revisionTime": "2017-08-16T18:14:22Z" 59 | }, 60 | { 61 | "checksumSHA1": "u3GOAJLmdvbuNUeUEcZSEAOeL/0=", 62 | "path": "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds", 63 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 64 | "revisionTime": "2017-08-16T18:14:22Z" 65 | }, 66 | { 67 | "checksumSHA1": "NUJUTWlc1sV8b7WjfiYc4JZbXl0=", 68 | "path": "github.com/aws/aws-sdk-go/aws/credentials/endpointcreds", 69 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 70 | "revisionTime": "2017-08-16T18:14:22Z" 71 | }, 72 | { 73 | "checksumSHA1": "JEYqmF83O5n5bHkupAzA6STm0no=", 74 | "path": "github.com/aws/aws-sdk-go/aws/credentials/stscreds", 75 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 76 | "revisionTime": "2017-08-16T18:14:22Z" 77 | }, 78 | { 79 | "checksumSHA1": "ZdtYh3ZHSgP/WEIaqwJHTEhpkbs=", 80 | "path": "github.com/aws/aws-sdk-go/aws/defaults", 81 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 82 | "revisionTime": "2017-08-16T18:14:22Z" 83 | }, 84 | { 85 | "checksumSHA1": "/EXbk/z2TWjWc1Hvb4QYs3Wmhb8=", 86 | "path": "github.com/aws/aws-sdk-go/aws/ec2metadata", 87 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 88 | "revisionTime": "2017-08-16T18:14:22Z" 89 | }, 90 | { 91 | "checksumSHA1": "NB8dESxzteU2rtzpWaiGnHOGBvI=", 92 | "path": "github.com/aws/aws-sdk-go/aws/endpoints", 93 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 94 | "revisionTime": "2017-08-16T18:14:22Z" 95 | }, 96 | { 97 | "checksumSHA1": "n/tgGgh0wICYu+VDYSqlsRy4w9s=", 98 | "path": "github.com/aws/aws-sdk-go/aws/request", 99 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 100 | "revisionTime": "2017-08-16T18:14:22Z" 101 | }, 102 | { 103 | "checksumSHA1": "SK5Mn4Ga9+equOQTYA1DTSb3LWY=", 104 | "path": "github.com/aws/aws-sdk-go/aws/session", 105 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 106 | "revisionTime": "2017-08-16T18:14:22Z" 107 | }, 108 | { 109 | "checksumSHA1": "iywvraxbXf3A/FOzFWjKfBBEQRA=", 110 | "path": "github.com/aws/aws-sdk-go/aws/signer/v4", 111 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 112 | "revisionTime": "2017-08-16T18:14:22Z" 113 | }, 114 | { 115 | "checksumSHA1": "04ypv4x12l4q0TksA1zEVsmgpvw=", 116 | "origin": "github.com/hashicorp/terraform/vendor/github.com/aws/aws-sdk-go/internal/shareddefaults", 117 | "path": "github.com/aws/aws-sdk-go/internal/shareddefaults", 118 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 119 | "revisionTime": "2017-08-16T17:38:16Z" 120 | }, 121 | { 122 | "checksumSHA1": "wk7EyvDaHwb5qqoOP/4d3cV0708=", 123 | "path": "github.com/aws/aws-sdk-go/private/protocol", 124 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 125 | "revisionTime": "2017-08-16T18:14:22Z" 126 | }, 127 | { 128 | "checksumSHA1": "ZqY5RWavBLWTo6j9xqdyBEaNFRk=", 129 | "path": "github.com/aws/aws-sdk-go/private/protocol/query", 130 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 131 | "revisionTime": "2017-08-16T18:14:22Z" 132 | }, 133 | { 134 | "checksumSHA1": "Drt1JfLMa0DQEZLWrnMlTWaIcC8=", 135 | "path": "github.com/aws/aws-sdk-go/private/protocol/query/queryutil", 136 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 137 | "revisionTime": "2017-08-16T18:14:22Z" 138 | }, 139 | { 140 | "checksumSHA1": "VCTh+dEaqqhog5ncy/WTt9+/gFM=", 141 | "path": "github.com/aws/aws-sdk-go/private/protocol/rest", 142 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 143 | "revisionTime": "2017-08-16T18:14:22Z" 144 | }, 145 | { 146 | "checksumSHA1": "ODo+ko8D6unAxZuN1jGzMcN4QCc=", 147 | "path": "github.com/aws/aws-sdk-go/private/protocol/restxml", 148 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 149 | "revisionTime": "2017-08-16T18:14:22Z" 150 | }, 151 | { 152 | "checksumSHA1": "0qYPUga28aQVkxZgBR3Z86AbGUQ=", 153 | "path": "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil", 154 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 155 | "revisionTime": "2017-08-16T18:14:22Z" 156 | }, 157 | { 158 | "checksumSHA1": "Eo9yODN5U99BK0pMzoqnBm7PCrY=", 159 | "path": "github.com/aws/aws-sdk-go/private/waiter", 160 | "revision": "d9caf90c8e590bdd2eaa074b1ff8c201dd56e57c", 161 | "revisionTime": "2017-03-08T00:55:36Z" 162 | }, 163 | { 164 | "checksumSHA1": "SEKg+cGyOj6dKdK5ltUHsoL4R4Y=", 165 | "path": "github.com/aws/aws-sdk-go/service/s3", 166 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 167 | "revisionTime": "2017-08-16T18:14:22Z" 168 | }, 169 | { 170 | "checksumSHA1": "MerduaV3PxtZAWvOGpgoBIglo38=", 171 | "path": "github.com/aws/aws-sdk-go/service/sts", 172 | "revision": "2063d937ea693f6f5c8b213906785ff9e36ba0b6", 173 | "revisionTime": "2017-08-16T18:14:22Z" 174 | }, 175 | { 176 | "checksumSHA1": "nqw2Qn5xUklssHTubS5HDvEL9L4=", 177 | "path": "github.com/bgentry/go-netrc/netrc", 178 | "revision": "9fd32a8b3d3d3f9d43c341bfe098430e07609480", 179 | "revisionTime": "2014-04-22T17:41:19Z" 180 | }, 181 | { 182 | "checksumSHA1": "Isa9x3nvIJ12hvgdvUUBty+yplU=", 183 | "origin": "github.com/hashicorp/terraform/vendor/github.com/bgentry/speakeasy", 184 | "path": "github.com/bgentry/speakeasy", 185 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 186 | "revisionTime": "2017-08-16T17:38:16Z" 187 | }, 188 | { 189 | "checksumSHA1": "OT4XN9z5k69e2RsMSpwW74B+yk4=", 190 | "path": "github.com/blang/semver", 191 | "revision": "2ee87856327ba09384cabd113bc6b5d174e9ec0f", 192 | "revisionTime": "2017-07-27T06:48:18Z" 193 | }, 194 | { 195 | "checksumSHA1": "mrz/kicZiUaHxkyfvC/DyQcr8Do=", 196 | "path": "github.com/davecgh/go-spew/spew", 197 | "revision": "adab96458c51a58dc1783b3335dcce5461522e75", 198 | "revisionTime": "2017-07-11T18:34:51Z" 199 | }, 200 | { 201 | "checksumSHA1": "h8AiJc65HX3Vp1vGkOBEA5umorQ=", 202 | "path": "github.com/fanatic/go-infoblox", 203 | "revision": "ece4e23a370d0bbac46d17f386f73d0d124a8d97", 204 | "revisionTime": "2018-04-14T18:49:06Z" 205 | }, 206 | { 207 | "checksumSHA1": "87LEfpY9cOk9CP7pWyIbmQ/6enU=", 208 | "comment": "v1.18.0", 209 | "path": "github.com/go-ini/ini", 210 | "revision": "c787282c39ac1fc618827141a1f762240def08a3", 211 | "revisionTime": "2017-08-13T05:22:30Z" 212 | }, 213 | { 214 | "checksumSHA1": "yqF125xVSkmfLpIVGrLlfE05IUk=", 215 | "path": "github.com/golang/protobuf/proto", 216 | "revision": "ab9f9a6dab164b7d1246e0e688b0ab7b94d8553e", 217 | "revisionTime": "2017-08-16T00:15:14Z" 218 | }, 219 | { 220 | "checksumSHA1": "VfkiItDBFFkZluaAMAzJipDXNBY=", 221 | "path": "github.com/golang/protobuf/ptypes", 222 | "revision": "ab9f9a6dab164b7d1246e0e688b0ab7b94d8553e", 223 | "revisionTime": "2017-08-16T00:15:14Z" 224 | }, 225 | { 226 | "checksumSHA1": "CUN+8uU3mWzv9JNB2RXTefAuBb4=", 227 | "path": "github.com/golang/protobuf/ptypes/any", 228 | "revision": "ab9f9a6dab164b7d1246e0e688b0ab7b94d8553e", 229 | "revisionTime": "2017-08-16T00:15:14Z" 230 | }, 231 | { 232 | "checksumSHA1": "hUjAj0dheFVDl84BAnSWj9qy2iY=", 233 | "path": "github.com/golang/protobuf/ptypes/duration", 234 | "revision": "ab9f9a6dab164b7d1246e0e688b0ab7b94d8553e", 235 | "revisionTime": "2017-08-16T00:15:14Z" 236 | }, 237 | { 238 | "checksumSHA1": "O2ItP5rmfrgxPufhjJXbFlXuyL8=", 239 | "path": "github.com/golang/protobuf/ptypes/timestamp", 240 | "revision": "ab9f9a6dab164b7d1246e0e688b0ab7b94d8553e", 241 | "revisionTime": "2017-08-16T00:15:14Z" 242 | }, 243 | { 244 | "checksumSHA1": "cdOCt0Yb+hdErz8NAQqayxPmRsY=", 245 | "path": "github.com/hashicorp/errwrap", 246 | "revision": "7554cd9344cec97297fa6649b055a8c98c2a1e55", 247 | "revisionTime": "2014-10-28T05:47:10Z" 248 | }, 249 | { 250 | "checksumSHA1": "b8F628srIitj5p7Y130xc9k0QWs=", 251 | "origin": "github.com/hashicorp/terraform/vendor/github.com/hashicorp/go-cleanhttp", 252 | "path": "github.com/hashicorp/go-cleanhttp", 253 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 254 | "revisionTime": "2017-08-16T17:38:16Z" 255 | }, 256 | { 257 | "checksumSHA1": "Glhu9BTy826XCLfMw7rexQ5mKeY=", 258 | "path": "github.com/hashicorp/go-getter", 259 | "revision": "6aae8e4e2dee8131187c6a54b52664796e5a02b0", 260 | "revisionTime": "2017-07-13T01:23:01Z" 261 | }, 262 | { 263 | "checksumSHA1": "9J+kDr29yDrwsdu2ULzewmqGjpA=", 264 | "path": "github.com/hashicorp/go-getter/helper/url", 265 | "revision": "6aae8e4e2dee8131187c6a54b52664796e5a02b0", 266 | "revisionTime": "2017-07-13T01:23:01Z" 267 | }, 268 | { 269 | "checksumSHA1": "miVF4/7JP0lRwZvFJGKwZWk7aAQ=", 270 | "path": "github.com/hashicorp/go-hclog", 271 | "revision": "b4e5765d1e5f00a0550911084f45f8214b5b83b9", 272 | "revisionTime": "2017-07-16T17:45:23Z" 273 | }, 274 | { 275 | "checksumSHA1": "g7uHECbzuaWwdxvwoyxBwgeERPk=", 276 | "path": "github.com/hashicorp/go-multierror", 277 | "revision": "83588e72410abfbe4df460eeb6f30841ae47d4c4", 278 | "revisionTime": "2017-06-22T06:09:55Z" 279 | }, 280 | { 281 | "checksumSHA1": "R6me0jVmcT/OPo80Fe0qo5fRwHc=", 282 | "path": "github.com/hashicorp/go-plugin", 283 | "revision": "a5174f84d7f8ff00fb07ab4ef1f380d32eee0e63", 284 | "revisionTime": "2017-08-16T15:18:19Z" 285 | }, 286 | { 287 | "checksumSHA1": "mAkPa/RLuIwN53GbwIEMATexams=", 288 | "path": "github.com/hashicorp/go-uuid", 289 | "revision": "64130c7a86d732268a38cb04cfbaf0cc987fda98", 290 | "revisionTime": "2016-07-17T02:21:40Z" 291 | }, 292 | { 293 | "checksumSHA1": "tUGxc7rfX0cmhOOUDhMuAZ9rWsA=", 294 | "path": "github.com/hashicorp/go-version", 295 | "revision": "03c5bf6be031b6dd45afec16b1cf94fc8938bc77", 296 | "revisionTime": "2017-02-02T08:07:59Z" 297 | }, 298 | { 299 | "checksumSHA1": "7JBkp3EZoc0MSbiyWfzVhO4RYoY=", 300 | "path": "github.com/hashicorp/hcl", 301 | "revision": "392dba7d905ed5d04a5794ba89f558b27e2ba1ca", 302 | "revisionTime": "2017-05-05T08:58:37Z" 303 | }, 304 | { 305 | "checksumSHA1": "XQmjDva9JCGGkIecOgwtBEMCJhU=", 306 | "path": "github.com/hashicorp/hcl/hcl/ast", 307 | "revision": "392dba7d905ed5d04a5794ba89f558b27e2ba1ca", 308 | "revisionTime": "2017-05-05T08:58:37Z" 309 | }, 310 | { 311 | "checksumSHA1": "teokXoyRXEJ0vZHOWBD11l5YFNI=", 312 | "path": "github.com/hashicorp/hcl/hcl/parser", 313 | "revision": "392dba7d905ed5d04a5794ba89f558b27e2ba1ca", 314 | "revisionTime": "2017-05-05T08:58:37Z" 315 | }, 316 | { 317 | "checksumSHA1": "z6wdP4mRw4GVjShkNHDaOWkbxS0=", 318 | "path": "github.com/hashicorp/hcl/hcl/scanner", 319 | "revision": "392dba7d905ed5d04a5794ba89f558b27e2ba1ca", 320 | "revisionTime": "2017-05-05T08:58:37Z" 321 | }, 322 | { 323 | "checksumSHA1": "oS3SCN9Wd6D8/LG0Yx1fu84a7gI=", 324 | "path": "github.com/hashicorp/hcl/hcl/strconv", 325 | "revision": "392dba7d905ed5d04a5794ba89f558b27e2ba1ca", 326 | "revisionTime": "2017-05-05T08:58:37Z" 327 | }, 328 | { 329 | "checksumSHA1": "c6yprzj06ASwCo18TtbbNNBHljA=", 330 | "path": "github.com/hashicorp/hcl/hcl/token", 331 | "revision": "392dba7d905ed5d04a5794ba89f558b27e2ba1ca", 332 | "revisionTime": "2017-05-05T08:58:37Z" 333 | }, 334 | { 335 | "checksumSHA1": "PwlfXt7mFS8UYzWxOK5DOq0yxS0=", 336 | "path": "github.com/hashicorp/hcl/json/parser", 337 | "revision": "392dba7d905ed5d04a5794ba89f558b27e2ba1ca", 338 | "revisionTime": "2017-05-05T08:58:37Z" 339 | }, 340 | { 341 | "checksumSHA1": "YdvFsNOMSWMLnY6fcliWQa0O5Fw=", 342 | "path": "github.com/hashicorp/hcl/json/scanner", 343 | "revision": "392dba7d905ed5d04a5794ba89f558b27e2ba1ca", 344 | "revisionTime": "2017-05-05T08:58:37Z" 345 | }, 346 | { 347 | "checksumSHA1": "fNlXQCQEnb+B3k5UDL/r15xtSJY=", 348 | "path": "github.com/hashicorp/hcl/json/token", 349 | "revision": "392dba7d905ed5d04a5794ba89f558b27e2ba1ca", 350 | "revisionTime": "2017-05-05T08:58:37Z" 351 | }, 352 | { 353 | "checksumSHA1": "M09yxoBoCEtG7EcHR8aEWLzMMJc=", 354 | "path": "github.com/hashicorp/hil", 355 | "revision": "fa9f258a92500514cc8e9c67020487709df92432", 356 | "revisionTime": "2017-02-13T18:49:38Z" 357 | }, 358 | { 359 | "checksumSHA1": "0S0KeBcfqVFYBPeZkuJ4fhQ5mCA=", 360 | "path": "github.com/hashicorp/hil/ast", 361 | "revision": "fa9f258a92500514cc8e9c67020487709df92432", 362 | "revisionTime": "2017-02-13T18:49:38Z" 363 | }, 364 | { 365 | "checksumSHA1": "P5PZ3k7SmqWmxgJ8Q0gLzeNpGhE=", 366 | "path": "github.com/hashicorp/hil/parser", 367 | "revision": "fa9f258a92500514cc8e9c67020487709df92432", 368 | "revisionTime": "2017-02-13T18:49:38Z" 369 | }, 370 | { 371 | "checksumSHA1": "ekmuVa77ebGDPXI+4FaskrID8lQ=", 372 | "path": "github.com/hashicorp/hil/scanner", 373 | "revision": "fa9f258a92500514cc8e9c67020487709df92432", 374 | "revisionTime": "2017-02-13T18:49:38Z" 375 | }, 376 | { 377 | "checksumSHA1": "vt+P9D2yWDO3gdvdgCzwqunlhxU=", 378 | "path": "github.com/hashicorp/logutils", 379 | "revision": "0dc08b1671f34c4250ce212759ebd880f743d883", 380 | "revisionTime": "2015-06-09T07:04:31Z" 381 | }, 382 | { 383 | "checksumSHA1": "KPrCMDPNcLmO7K6xPcJSl86LwPk=", 384 | "path": "github.com/hashicorp/terraform/config", 385 | "revision": "2041053ee9444fa8175a298093b55a89586a1823", 386 | "revisionTime": "2017-08-02T18:39:14Z", 387 | "version": "v0.10.0", 388 | "versionExact": "v0.10.0" 389 | }, 390 | { 391 | "checksumSHA1": "uPCJ6seQo9kvoNSfwNWKX9KzVMk=", 392 | "path": "github.com/hashicorp/terraform/config/module", 393 | "revision": "2041053ee9444fa8175a298093b55a89586a1823", 394 | "revisionTime": "2017-08-02T18:39:14Z", 395 | "version": "v0.10.0", 396 | "versionExact": "v0.10.0" 397 | }, 398 | { 399 | "checksumSHA1": "w+l+UGTmwYNJ+L0p2vTd6+yqjok=", 400 | "path": "github.com/hashicorp/terraform/dag", 401 | "revision": "2041053ee9444fa8175a298093b55a89586a1823", 402 | "revisionTime": "2017-08-02T18:39:14Z", 403 | "version": "v0.10.0", 404 | "versionExact": "v0.10.0" 405 | }, 406 | { 407 | "checksumSHA1": "P8gNPDuOzmiK4Lz9xG7OBy4Rlm8=", 408 | "path": "github.com/hashicorp/terraform/flatmap", 409 | "revision": "2041053ee9444fa8175a298093b55a89586a1823", 410 | "revisionTime": "2017-08-02T18:39:14Z", 411 | "version": "v0.10.0", 412 | "versionExact": "v0.10.0" 413 | }, 414 | { 415 | "checksumSHA1": "uT6Q9RdSRAkDjyUgQlJ2XKJRab4=", 416 | "path": "github.com/hashicorp/terraform/helper/config", 417 | "revision": "2041053ee9444fa8175a298093b55a89586a1823", 418 | "revisionTime": "2017-08-02T18:39:14Z", 419 | "version": "v0.10.0", 420 | "versionExact": "v0.10.0" 421 | }, 422 | { 423 | "checksumSHA1": "Vbo55GDzPgG/L/+W2pcvDhxrPZc=", 424 | "path": "github.com/hashicorp/terraform/helper/experiment", 425 | "revision": "2041053ee9444fa8175a298093b55a89586a1823", 426 | "revisionTime": "2017-08-02T18:39:14Z", 427 | "version": "v0.10.0", 428 | "versionExact": "v0.10.0" 429 | }, 430 | { 431 | "checksumSHA1": "BmIPKTr0zDutSJdyq7pYXrK1I3E=", 432 | "path": "github.com/hashicorp/terraform/helper/hashcode", 433 | "revision": "2041053ee9444fa8175a298093b55a89586a1823", 434 | "revisionTime": "2017-08-02T18:39:14Z", 435 | "version": "v0.10.0", 436 | "versionExact": "v0.10.0" 437 | }, 438 | { 439 | "checksumSHA1": "B267stWNQd0/pBTXHfI/tJsxzfc=", 440 | "path": "github.com/hashicorp/terraform/helper/hilmapstructure", 441 | "revision": "2041053ee9444fa8175a298093b55a89586a1823", 442 | "revisionTime": "2017-08-02T18:39:14Z", 443 | "version": "v0.10.0", 444 | "versionExact": "v0.10.0" 445 | }, 446 | { 447 | "checksumSHA1": "2wJa9F3BGlbe2DNqH5lb5POayRI=", 448 | "path": "github.com/hashicorp/terraform/helper/logging", 449 | "revision": "2041053ee9444fa8175a298093b55a89586a1823", 450 | "revisionTime": "2017-08-02T18:39:14Z", 451 | "version": "v0.10.0", 452 | "versionExact": "v0.10.0" 453 | }, 454 | { 455 | "checksumSHA1": "dhU2woQaSEI2OnbYLdkHxf7/nu8=", 456 | "path": "github.com/hashicorp/terraform/helper/resource", 457 | "revision": "2041053ee9444fa8175a298093b55a89586a1823", 458 | "revisionTime": "2017-08-02T18:39:14Z", 459 | "version": "v0.10.0", 460 | "versionExact": "v0.10.0" 461 | }, 462 | { 463 | "checksumSHA1": "0smlb90amL15c/6nWtW4DV6Lqh8=", 464 | "path": "github.com/hashicorp/terraform/helper/schema", 465 | "revision": "2041053ee9444fa8175a298093b55a89586a1823", 466 | "revisionTime": "2017-08-02T18:39:14Z", 467 | "version": "v0.10.0", 468 | "versionExact": "v0.10.0" 469 | }, 470 | { 471 | "checksumSHA1": "1yCGh/Wl4H4ODBBRmIRFcV025b0=", 472 | "path": "github.com/hashicorp/terraform/helper/shadow", 473 | "revision": "2041053ee9444fa8175a298093b55a89586a1823", 474 | "revisionTime": "2017-08-02T18:39:14Z", 475 | "version": "v0.10.0", 476 | "versionExact": "v0.10.0" 477 | }, 478 | { 479 | "checksumSHA1": "yFWmdS6yEJZpRJzUqd/mULqCYGk=", 480 | "path": "github.com/hashicorp/terraform/moduledeps", 481 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 482 | "revisionTime": "2017-08-16T17:38:16Z" 483 | }, 484 | { 485 | "checksumSHA1": "4ODNVUds3lyBf7gV02X1EeYR4GA=", 486 | "path": "github.com/hashicorp/terraform/plugin", 487 | "revision": "2041053ee9444fa8175a298093b55a89586a1823", 488 | "revisionTime": "2017-08-02T18:39:14Z", 489 | "version": "v0.10.0", 490 | "versionExact": "v0.10.0" 491 | }, 492 | { 493 | "checksumSHA1": "EHHrYLqEpTXzJMmZYMMFTGWDbaE=", 494 | "path": "github.com/hashicorp/terraform/plugin/discovery", 495 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 496 | "revisionTime": "2017-08-16T17:38:16Z" 497 | }, 498 | { 499 | "checksumSHA1": "ksfNQjZs/6llziARojABd6iuvdw=", 500 | "path": "github.com/hashicorp/terraform/terraform", 501 | "revision": "2041053ee9444fa8175a298093b55a89586a1823", 502 | "revisionTime": "2017-08-02T18:39:14Z", 503 | "version": "v0.10.0", 504 | "versionExact": "v0.10.0" 505 | }, 506 | { 507 | "checksumSHA1": "ZhK6IO2XN81Y+3RAjTcVm1Ic7oU=", 508 | "path": "github.com/hashicorp/yamux", 509 | "revision": "d1caa6c97c9fc1cc9e83bbe34d0603f9ff0ce8bd", 510 | "revisionTime": "2016-07-20T23:31:40Z" 511 | }, 512 | { 513 | "checksumSHA1": "0ZrwvB6KoGPj2PoDNSEJwxQ6Mog=", 514 | "path": "github.com/jmespath/go-jmespath", 515 | "revision": "bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d", 516 | "revisionTime": "2016-08-03T19:07:31Z" 517 | }, 518 | { 519 | "checksumSHA1": "1otkAg+0Q9NksNSuQ3ijCW0xHxE=", 520 | "origin": "github.com/hashicorp/terraform/vendor/github.com/mattn/go-isatty", 521 | "path": "github.com/mattn/go-isatty", 522 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 523 | "revisionTime": "2017-08-16T17:38:16Z" 524 | }, 525 | { 526 | "checksumSHA1": "KXrCoifaKi3Wy4zbCfXTtM/FO48=", 527 | "origin": "github.com/hashicorp/terraform/vendor/github.com/mitchellh/cli", 528 | "path": "github.com/mitchellh/cli", 529 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 530 | "revisionTime": "2017-08-16T17:38:16Z" 531 | }, 532 | { 533 | "checksumSHA1": "+p4JY4wmFQAppCdlrJ8Kxybmht8=", 534 | "path": "github.com/mitchellh/copystructure", 535 | "revision": "d23ffcb85de31694d6ccaa23ccb4a03e55c1303f", 536 | "revisionTime": "2017-05-25T01:39:02Z" 537 | }, 538 | { 539 | "checksumSHA1": "V/quM7+em2ByJbWBLOsEwnY3j/Q=", 540 | "path": "github.com/mitchellh/go-homedir", 541 | "revision": "b8bc1bf767474819792c23f32d8286a45736f1c6", 542 | "revisionTime": "2016-12-03T19:45:07Z" 543 | }, 544 | { 545 | "checksumSHA1": "6TBW88DSxRHf4WvOC9K5ilBZx/8=", 546 | "path": "github.com/mitchellh/go-testing-interface", 547 | "revision": "9a441910b16872f7b8283682619b3761a9aa2222", 548 | "revisionTime": "2017-07-30T05:09:07Z" 549 | }, 550 | { 551 | "checksumSHA1": "tWUjKyFOGJtYExocPWVYiXBYsfE=", 552 | "path": "github.com/mitchellh/hashstructure", 553 | "revision": "2bca23e0e452137f789efbc8610126fd8b94f73b", 554 | "revisionTime": "2017-06-09T04:59:27Z" 555 | }, 556 | { 557 | "checksumSHA1": "EHjhpHipgm+XGccrRAms9AW3Ewk=", 558 | "path": "github.com/mitchellh/mapstructure", 559 | "revision": "d0303fe809921458f417bcf828397a65db30a7e4", 560 | "revisionTime": "2017-05-23T03:00:23Z" 561 | }, 562 | { 563 | "checksumSHA1": "AMU63CNOg4XmIhVR/S/Xttt1/f0=", 564 | "path": "github.com/mitchellh/reflectwalk", 565 | "revision": "63d60e9d0dbc60cf9164e6510889b0db6683d98c", 566 | "revisionTime": "2017-07-26T20:21:17Z" 567 | }, 568 | { 569 | "checksumSHA1": "6OEUkwOM0qgI6YxR+BDEn6YMvpU=", 570 | "origin": "github.com/hashicorp/terraform/vendor/github.com/posener/complete", 571 | "path": "github.com/posener/complete", 572 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 573 | "revisionTime": "2017-08-16T17:38:16Z" 574 | }, 575 | { 576 | "checksumSHA1": "NB7uVS0/BJDmNu68vPAlbrq4TME=", 577 | "origin": "github.com/hashicorp/terraform/vendor/github.com/posener/complete/cmd", 578 | "path": "github.com/posener/complete/cmd", 579 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 580 | "revisionTime": "2017-08-16T17:38:16Z" 581 | }, 582 | { 583 | "checksumSHA1": "kuS9vs+TMQzTGzXteL6EZ5HuKrU=", 584 | "origin": "github.com/hashicorp/terraform/vendor/github.com/posener/complete/cmd/install", 585 | "path": "github.com/posener/complete/cmd/install", 586 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 587 | "revisionTime": "2017-08-16T17:38:16Z" 588 | }, 589 | { 590 | "checksumSHA1": "DMo94FwJAm9ZCYCiYdJU2+bh4no=", 591 | "origin": "github.com/hashicorp/terraform/vendor/github.com/posener/complete/match", 592 | "path": "github.com/posener/complete/match", 593 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 594 | "revisionTime": "2017-08-16T17:38:16Z" 595 | }, 596 | { 597 | "checksumSHA1": "aq6xeiFQsEmEZ5KwdLSwT7h9A/w=", 598 | "path": "github.com/prudhvitella/terraform-provider-infoblox", 599 | "revision": "f0facf84e13dc9086a0ee8a535dcfd41c2c899d4", 600 | "revisionTime": "2018-11-08T11:05:57Z" 601 | }, 602 | { 603 | "checksumSHA1": "tH1nSqrdeabNlB+Gf8g+rm7lX7w=", 604 | "path": "github.com/prudhvitella/terraform-provider-infoblox/infoblox", 605 | "revision": "f0facf84e13dc9086a0ee8a535dcfd41c2c899d4", 606 | "revisionTime": "2018-11-08T11:05:57Z" 607 | }, 608 | { 609 | "checksumSHA1": "zmC8/3V4ls53DJlNTKDZwPSC/dA=", 610 | "path": "github.com/satori/go.uuid", 611 | "revision": "5bf94b69c6b68ee1b541973bb8e1144db23a194b", 612 | "revisionTime": "2017-03-21T23:07:31Z" 613 | }, 614 | { 615 | "checksumSHA1": "z2kAtVle4NFV2OExI85fZoTcsI4=", 616 | "path": "github.com/ulikunitz/xz", 617 | "revision": "0c6b41e72360850ca4f98dc341fd999726ea007f", 618 | "revisionTime": "2017-06-05T21:53:11Z" 619 | }, 620 | { 621 | "checksumSHA1": "vjnTkzNrMs5Xj6so/fq0mQ6dT1c=", 622 | "path": "github.com/ulikunitz/xz/internal/hash", 623 | "revision": "0c6b41e72360850ca4f98dc341fd999726ea007f", 624 | "revisionTime": "2017-06-05T21:53:11Z" 625 | }, 626 | { 627 | "checksumSHA1": "m0pm57ASBK/CTdmC0ppRHO17mBs=", 628 | "path": "github.com/ulikunitz/xz/internal/xlog", 629 | "revision": "0c6b41e72360850ca4f98dc341fd999726ea007f", 630 | "revisionTime": "2017-06-05T21:53:11Z" 631 | }, 632 | { 633 | "checksumSHA1": "2vZw6zc8xuNlyVz2QKvdlNSZQ1U=", 634 | "path": "github.com/ulikunitz/xz/lzma", 635 | "revision": "0c6b41e72360850ca4f98dc341fd999726ea007f", 636 | "revisionTime": "2017-06-05T21:53:11Z" 637 | }, 638 | { 639 | "checksumSHA1": "UWjVYmoHlIfHzVIskELHiJQtMOI=", 640 | "path": "golang.org/x/crypto/bcrypt", 641 | "revision": "b176d7def5d71bdd214203491f89843ed217f420", 642 | "revisionTime": "2017-07-23T04:49:35Z" 643 | }, 644 | { 645 | "checksumSHA1": "oVPHWesOmZ02vLq2fglGvf+AMgk=", 646 | "path": "golang.org/x/crypto/blowfish", 647 | "revision": "b176d7def5d71bdd214203491f89843ed217f420", 648 | "revisionTime": "2017-07-23T04:49:35Z" 649 | }, 650 | { 651 | "checksumSHA1": "TT1rac6kpQp2vz24m5yDGUNQ/QQ=", 652 | "origin": "github.com/hashicorp/terraform/vendor/golang.org/x/crypto/cast5", 653 | "path": "golang.org/x/crypto/cast5", 654 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 655 | "revisionTime": "2017-08-16T17:38:16Z" 656 | }, 657 | { 658 | "checksumSHA1": "IIhFTrLlmlc6lEFSitqi4aw2lw0=", 659 | "origin": "github.com/hashicorp/terraform/vendor/golang.org/x/crypto/openpgp", 660 | "path": "golang.org/x/crypto/openpgp", 661 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 662 | "revisionTime": "2017-08-16T17:38:16Z" 663 | }, 664 | { 665 | "checksumSHA1": "olOKkhrdkYQHZ0lf1orrFQPQrv4=", 666 | "origin": "github.com/hashicorp/terraform/vendor/golang.org/x/crypto/openpgp/armor", 667 | "path": "golang.org/x/crypto/openpgp/armor", 668 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 669 | "revisionTime": "2017-08-16T17:38:16Z" 670 | }, 671 | { 672 | "checksumSHA1": "eo/KtdjieJQXH7Qy+faXFcF70ME=", 673 | "origin": "github.com/hashicorp/terraform/vendor/golang.org/x/crypto/openpgp/elgamal", 674 | "path": "golang.org/x/crypto/openpgp/elgamal", 675 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 676 | "revisionTime": "2017-08-16T17:38:16Z" 677 | }, 678 | { 679 | "checksumSHA1": "rlxVSaGgqdAgwblsErxTxIfuGfg=", 680 | "origin": "github.com/hashicorp/terraform/vendor/golang.org/x/crypto/openpgp/errors", 681 | "path": "golang.org/x/crypto/openpgp/errors", 682 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 683 | "revisionTime": "2017-08-16T17:38:16Z" 684 | }, 685 | { 686 | "checksumSHA1": "LWdaR8Q9yn6eBCcnGl0HvJRDUBE=", 687 | "origin": "github.com/hashicorp/terraform/vendor/golang.org/x/crypto/openpgp/packet", 688 | "path": "golang.org/x/crypto/openpgp/packet", 689 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 690 | "revisionTime": "2017-08-16T17:38:16Z" 691 | }, 692 | { 693 | "checksumSHA1": "s2qT4UwvzBSkzXuiuMkowif1Olw=", 694 | "origin": "github.com/hashicorp/terraform/vendor/golang.org/x/crypto/openpgp/s2k", 695 | "path": "golang.org/x/crypto/openpgp/s2k", 696 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 697 | "revisionTime": "2017-08-16T17:38:16Z" 698 | }, 699 | { 700 | "checksumSHA1": "dr5+PfIRzXeN+l1VG+s0lea9qz8=", 701 | "path": "golang.org/x/net/context", 702 | "revision": "1c05540f6879653db88113bc4a2b70aec4bd491f", 703 | "revisionTime": "2017-08-04T00:04:37Z" 704 | }, 705 | { 706 | "checksumSHA1": "vqc3a+oTUGX8PmD0TS+qQ7gmN8I=", 707 | "origin": "github.com/hashicorp/terraform/vendor/golang.org/x/net/html", 708 | "path": "golang.org/x/net/html", 709 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 710 | "revisionTime": "2017-08-16T17:38:16Z" 711 | }, 712 | { 713 | "checksumSHA1": "00eQaGynDYrv3tL+C7l9xH0IDZg=", 714 | "origin": "github.com/hashicorp/terraform/vendor/golang.org/x/net/html/atom", 715 | "path": "golang.org/x/net/html/atom", 716 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 717 | "revisionTime": "2017-08-16T17:38:16Z" 718 | }, 719 | { 720 | "checksumSHA1": "CLeUeDDAFQGbUNyRIryrVXqkWf0=", 721 | "path": "golang.org/x/net/http2", 722 | "revision": "1c05540f6879653db88113bc4a2b70aec4bd491f", 723 | "revisionTime": "2017-08-04T00:04:37Z" 724 | }, 725 | { 726 | "checksumSHA1": "ezWhc7n/FtqkLDQKeU2JbW+80tE=", 727 | "path": "golang.org/x/net/http2/hpack", 728 | "revision": "1c05540f6879653db88113bc4a2b70aec4bd491f", 729 | "revisionTime": "2017-08-04T00:04:37Z" 730 | }, 731 | { 732 | "checksumSHA1": "g/Z/Ka0VgJESgQK7/SJCjm/aX0I=", 733 | "path": "golang.org/x/net/idna", 734 | "revision": "1c05540f6879653db88113bc4a2b70aec4bd491f", 735 | "revisionTime": "2017-08-04T00:04:37Z" 736 | }, 737 | { 738 | "checksumSHA1": "UxahDzW2v4mf/+aFxruuupaoIwo=", 739 | "path": "golang.org/x/net/internal/timeseries", 740 | "revision": "1c05540f6879653db88113bc4a2b70aec4bd491f", 741 | "revisionTime": "2017-08-04T00:04:37Z" 742 | }, 743 | { 744 | "checksumSHA1": "3xyuaSNmClqG4YWC7g0isQIbUTc=", 745 | "path": "golang.org/x/net/lex/httplex", 746 | "revision": "1c05540f6879653db88113bc4a2b70aec4bd491f", 747 | "revisionTime": "2017-08-04T00:04:37Z" 748 | }, 749 | { 750 | "checksumSHA1": "txD8w9+dmFn4uG8BbqdZwXawT6E=", 751 | "path": "golang.org/x/net/publicsuffix", 752 | "revision": "1c05540f6879653db88113bc4a2b70aec4bd491f", 753 | "revisionTime": "2017-08-04T00:04:37Z" 754 | }, 755 | { 756 | "checksumSHA1": "u/r66lwYfgg682u5hZG7/E7+VCY=", 757 | "path": "golang.org/x/net/trace", 758 | "revision": "1c05540f6879653db88113bc4a2b70aec4bd491f", 759 | "revisionTime": "2017-08-04T00:04:37Z" 760 | }, 761 | { 762 | "checksumSHA1": "Tkb1hBdBWeO7SGjixS2Hm48F6+s=", 763 | "origin": "github.com/hashicorp/terraform/vendor/golang.org/x/sys/unix", 764 | "path": "golang.org/x/sys/unix", 765 | "revision": "08339b004b5a0a02e4487ace2c30a3b2cc002875", 766 | "revisionTime": "2017-08-16T17:38:16Z" 767 | }, 768 | { 769 | "checksumSHA1": "ZQdHbB9VYCXwQ+9/CmZPhJv0+SM=", 770 | "path": "golang.org/x/text/internal/gen", 771 | "revision": "e56139fd9c5bc7244c76116c68e500765bb6db6b", 772 | "revisionTime": "2017-07-04T19:41:35Z" 773 | }, 774 | { 775 | "checksumSHA1": "47nwiUyVBY2RKoEGXmCSvusY4Js=", 776 | "path": "golang.org/x/text/internal/triegen", 777 | "revision": "e56139fd9c5bc7244c76116c68e500765bb6db6b", 778 | "revisionTime": "2017-07-04T19:41:35Z" 779 | }, 780 | { 781 | "checksumSHA1": "Yd5wMObzagIfCiKLpZbtBIrOUA4=", 782 | "path": "golang.org/x/text/internal/ucd", 783 | "revision": "e56139fd9c5bc7244c76116c68e500765bb6db6b", 784 | "revisionTime": "2017-07-04T19:41:35Z" 785 | }, 786 | { 787 | "checksumSHA1": "faFDXp++cLjLBlvsr+izZ+go1WU=", 788 | "path": "golang.org/x/text/secure/bidirule", 789 | "revision": "e56139fd9c5bc7244c76116c68e500765bb6db6b", 790 | "revisionTime": "2017-07-04T19:41:35Z" 791 | }, 792 | { 793 | "checksumSHA1": "ziMb9+ANGRJSSIuxYdRbA+cDRBQ=", 794 | "path": "golang.org/x/text/transform", 795 | "revision": "e56139fd9c5bc7244c76116c68e500765bb6db6b", 796 | "revisionTime": "2017-07-04T19:41:35Z" 797 | }, 798 | { 799 | "checksumSHA1": "KG+XZAbxdkpBm3Fa3bJ3Ylq8CKI=", 800 | "path": "golang.org/x/text/unicode/bidi", 801 | "revision": "e56139fd9c5bc7244c76116c68e500765bb6db6b", 802 | "revisionTime": "2017-07-04T19:41:35Z" 803 | }, 804 | { 805 | "checksumSHA1": "u67CNB7snnIRQfOV+pE1mwCDkNc=", 806 | "path": "golang.org/x/text/unicode/cldr", 807 | "revision": "e56139fd9c5bc7244c76116c68e500765bb6db6b", 808 | "revisionTime": "2017-07-04T19:41:35Z" 809 | }, 810 | { 811 | "checksumSHA1": "Anof4bt0AU+Sa3R8Rq0KBnlpbaQ=", 812 | "path": "golang.org/x/text/unicode/norm", 813 | "revision": "e56139fd9c5bc7244c76116c68e500765bb6db6b", 814 | "revisionTime": "2017-07-04T19:41:35Z" 815 | }, 816 | { 817 | "checksumSHA1": "5R2IZ5umPfkD5QKt3pwrbIgmrDk=", 818 | "path": "golang.org/x/text/unicode/rangetable", 819 | "revision": "e56139fd9c5bc7244c76116c68e500765bb6db6b", 820 | "revisionTime": "2017-07-04T19:41:35Z" 821 | }, 822 | { 823 | "checksumSHA1": "AvVpgwhxhJgjoSledwDtYrEKVE4=", 824 | "path": "google.golang.org/genproto/googleapis/rpc/status", 825 | "revision": "6b7d9516179cd47f4714cfeb0103ad1dede756c4", 826 | "revisionTime": "2017-08-15T00:32:06Z" 827 | }, 828 | { 829 | "checksumSHA1": "Gxms+40SIqnvtdtJ1B/qMDEocOU=", 830 | "path": "google.golang.org/grpc", 831 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 832 | "revisionTime": "2017-08-15T17:45:05Z" 833 | }, 834 | { 835 | "checksumSHA1": "/eTpFgjvMq5Bc9hYnw5fzKG4B6I=", 836 | "path": "google.golang.org/grpc/codes", 837 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 838 | "revisionTime": "2017-08-15T17:45:05Z" 839 | }, 840 | { 841 | "checksumSHA1": "XH2WYcDNwVO47zYShREJjcYXm0Y=", 842 | "path": "google.golang.org/grpc/connectivity", 843 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 844 | "revisionTime": "2017-08-15T17:45:05Z" 845 | }, 846 | { 847 | "checksumSHA1": "5ylThBvJnIcyWhL17AC9+Sdbw2E=", 848 | "path": "google.golang.org/grpc/credentials", 849 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 850 | "revisionTime": "2017-08-15T17:45:05Z" 851 | }, 852 | { 853 | "checksumSHA1": "2NbY9kmMweE4VUsruRsvmViVnNg=", 854 | "path": "google.golang.org/grpc/grpclb/grpc_lb_v1", 855 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 856 | "revisionTime": "2017-08-15T17:45:05Z" 857 | }, 858 | { 859 | "checksumSHA1": "ntHev01vgZgeIh5VFRmbLx/BSTo=", 860 | "path": "google.golang.org/grpc/grpclog", 861 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 862 | "revisionTime": "2017-08-15T17:45:05Z" 863 | }, 864 | { 865 | "checksumSHA1": "pc9cweMiKQ5hVMuO9UoMGdbizaY=", 866 | "path": "google.golang.org/grpc/health", 867 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 868 | "revisionTime": "2017-08-15T17:45:05Z" 869 | }, 870 | { 871 | "checksumSHA1": "W5KfI1NIGJt7JaVnLzefDZr3+4s=", 872 | "path": "google.golang.org/grpc/health/grpc_health_v1", 873 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 874 | "revisionTime": "2017-08-15T17:45:05Z" 875 | }, 876 | { 877 | "checksumSHA1": "U9vDe05/tQrvFBojOQX8Xk12W9I=", 878 | "path": "google.golang.org/grpc/internal", 879 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 880 | "revisionTime": "2017-08-15T17:45:05Z" 881 | }, 882 | { 883 | "checksumSHA1": "hcuHgKp8W0wIzoCnNfKI8NUss5o=", 884 | "path": "google.golang.org/grpc/keepalive", 885 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 886 | "revisionTime": "2017-08-15T17:45:05Z" 887 | }, 888 | { 889 | "checksumSHA1": "N++Ur11m6Dq3j14/Hc2Kqmxroag=", 890 | "path": "google.golang.org/grpc/metadata", 891 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 892 | "revisionTime": "2017-08-15T17:45:05Z" 893 | }, 894 | { 895 | "checksumSHA1": "bYKw8OIjj/ybY68eGqy7zqq6qmE=", 896 | "path": "google.golang.org/grpc/naming", 897 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 898 | "revisionTime": "2017-08-15T17:45:05Z" 899 | }, 900 | { 901 | "checksumSHA1": "n5EgDdBqFMa2KQFhtl+FF/4gIFo=", 902 | "path": "google.golang.org/grpc/peer", 903 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 904 | "revisionTime": "2017-08-15T17:45:05Z" 905 | }, 906 | { 907 | "checksumSHA1": "53Mbn2VqooOk47EWLHHFpKEOVwE=", 908 | "path": "google.golang.org/grpc/stats", 909 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 910 | "revisionTime": "2017-08-15T17:45:05Z" 911 | }, 912 | { 913 | "checksumSHA1": "3Dwz4RLstDHMPyDA7BUsYe+JP4w=", 914 | "path": "google.golang.org/grpc/status", 915 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 916 | "revisionTime": "2017-08-15T17:45:05Z" 917 | }, 918 | { 919 | "checksumSHA1": "qvArRhlrww5WvRmbyMF2mUfbJew=", 920 | "path": "google.golang.org/grpc/tap", 921 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 922 | "revisionTime": "2017-08-15T17:45:05Z" 923 | }, 924 | { 925 | "checksumSHA1": "i0QoEdca9asrdLleMx5NNOvDJBQ=", 926 | "path": "google.golang.org/grpc/transport", 927 | "revision": "bfaf0423469fc4f95e9eac7e3eec0b2abb46fcca", 928 | "revisionTime": "2017-08-15T17:45:05Z" 929 | } 930 | ], 931 | "rootPath": "github.com/prudhvitella/terraform-provider-infoblox" 932 | } 933 | --------------------------------------------------------------------------------