From 4a9487f96aacf4e8372d4580242dc80ad92eb502 Mon Sep 17 00:00:00 2001 From: Phil Clay Date: Mon, 5 Feb 2018 16:08:49 -0800 Subject: [PATCH] Lazily initialize and bind the connection. This will avoid connecting to LDAP if, for example, you have defined the ldap provider and some ldap resources in your terraform config, but the ldap resource count is 0 (say if the count was calculated dynamically). Note that you can also now prevent the provider for prompting for bind credentials if you specify bogus credentials in the provider configuration (assuming the ldap resource counts are zero) --- config.go | 58 +++++++++++++++++++++++++++-------------- provider.go | 11 ++------ resource_ldap_object.go | 39 ++++++++++++++++++++------- 3 files changed, 70 insertions(+), 38 deletions(-) diff --git a/config.go b/config.go index 28666c4..0acedbb 100644 --- a/config.go +++ b/config.go @@ -3,6 +3,7 @@ package main import ( "crypto/tls" "fmt" + "sync" "gopkg.in/ldap.v2" ) @@ -16,29 +17,46 @@ type Config struct { BindPassword string } +// The lazily initialized response from the first initiateAndBind attempt. +var initiateAndBindResponse *InitiateAndBindResponse +var once sync.Once + +type InitiateAndBindResponse struct { + Connection *ldap.Conn + Err error +} + func (c *Config) initiateAndBind() (*ldap.Conn, error) { - // TODO: should we handle UDP ? - connection, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", c.LDAPHost, c.LDAPPort)) - if err != nil { - return nil, err - } - - // handle TLS - if c.UseTLS { - //TODO: Finish the TLS integration - err = connection.StartTLS(&tls.Config{InsecureSkipVerify: true}) + once.Do(func() { + initiateAndBindResponse = &InitiateAndBindResponse{} + + // TODO: should we handle UDP ? + connection, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", c.LDAPHost, c.LDAPPort)) if err != nil { - return nil, err + initiateAndBindResponse.Err = err + return } - } - // bind to current connection - err = connection.Bind(c.BindUser, c.BindPassword) - if err != nil { - connection.Close() - return nil, err - } + // handle TLS + if c.UseTLS { + //TODO: Finish the TLS integration + err = connection.StartTLS(&tls.Config{InsecureSkipVerify: true}) + if err != nil { + connection.Close() + initiateAndBindResponse.Err = err + return + } + } + + // bind to current connection + err = connection.Bind(c.BindUser, c.BindPassword) + if err != nil { + connection.Close() + initiateAndBindResponse.Err = err + } - // return the LDAP connection - return connection, nil + // return the LDAP connection + initiateAndBindResponse.Connection = connection + }) + return initiateAndBindResponse.Connection, initiateAndBindResponse.Err } diff --git a/provider.go b/provider.go index f33ab0a..15428f2 100644 --- a/provider.go +++ b/provider.go @@ -50,18 +50,11 @@ func Provider() terraform.ResourceProvider { } func configureProvider(d *schema.ResourceData) (interface{}, error) { - config := Config{ + return &Config{ LDAPHost: d.Get("ldap_host").(string), LDAPPort: d.Get("ldap_port").(int), UseTLS: d.Get("use_tls").(bool), BindUser: d.Get("bind_user").(string), BindPassword: d.Get("bind_password").(string), - } - - connection, err := config.initiateAndBind() - if err != nil { - return nil, err - } - - return connection, nil + }, nil } diff --git a/resource_ldap_object.go b/resource_ldap_object.go index e4d9288..bbc0aae 100644 --- a/resource_ldap_object.go +++ b/resource_ldap_object.go @@ -114,7 +114,11 @@ func resourceLDAPObjectImport(d *schema.ResourceData, meta interface{}) (importe } func resourceLDAPObjectExists(d *schema.ResourceData, meta interface{}) (b bool, e error) { - conn := meta.(*ldap.Conn) + config := meta.(*Config) + conn, err := config.initiateAndBind() + if err != nil { + return false, err + } dn := d.Get("dn").(string) log.Printf("[DEBUG] ldap_object::exists - checking if %q exists", dn) @@ -135,7 +139,8 @@ func resourceLDAPObjectExists(d *schema.ResourceData, meta interface{}) (b bool, nil, ) - _, err := conn.Search(request) + var _ *ldap.SearchResult + _, err = conn.Search(request) if err != nil { if err, ok := err.(*ldap.Error); ok { if err.ResultCode == 32 { // no such object @@ -152,7 +157,11 @@ func resourceLDAPObjectExists(d *schema.ResourceData, meta interface{}) (b bool, } func resourceLDAPObjectCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*ldap.Conn) + config := meta.(*Config) + client, err := config.initiateAndBind() + if err != nil { + return err + } dn := d.Get("dn").(string) log.Printf("[DEBUG] ldap_object::create - creating a new object under %q", dn) @@ -193,7 +202,7 @@ func resourceLDAPObjectCreate(d *schema.ResourceData, meta interface{}) error { } } - err := client.Add(request) + err = client.Add(request) if err != nil { return err } @@ -209,7 +218,11 @@ func resourceLDAPObjectRead(d *schema.ResourceData, meta interface{}) error { } func resourceLDAPObjectUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*ldap.Conn) + config := meta.(*Config) + client, err := config.initiateAndBind() + if err != nil { + return err + } log.Printf("[DEBUG] ldap_object::update - performing update on %q", d.Id()) @@ -255,7 +268,7 @@ func resourceLDAPObjectUpdate(d *schema.ResourceData, meta interface{}) error { } } - err := client.Modify(request) + err = client.Modify(request) if err != nil { log.Printf("[ERROR] ldap_object::update - error modifying LDAP object %q with values %v", d.Id(), err) return err @@ -264,14 +277,18 @@ func resourceLDAPObjectUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceLDAPObjectDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*ldap.Conn) + config := meta.(*Config) + client, err := config.initiateAndBind() + if err != nil { + return err + } dn := d.Get("dn").(string) log.Printf("[DEBUG] ldap_object::delete - removing %q", dn) request := ldap.NewDelRequest(dn, nil) - err := client.Del(request) + err = client.Del(request) if err != nil { log.Printf("[ERROR] ldap_object::delete - error removing %q: %v", dn, err) return err @@ -281,7 +298,11 @@ func resourceLDAPObjectDelete(d *schema.ResourceData, meta interface{}) error { } func readLDAPObjectImpl(d *schema.ResourceData, meta interface{}, updateState bool) error { - client := meta.(*ldap.Conn) + config := meta.(*Config) + client, err := config.initiateAndBind() + if err != nil { + return err + } dn := d.Get("dn").(string) log.Printf("[DEBUG] ldap_object::read - looking for object %q", dn)