From 8055dffe8b9f5ca1db82617e8f513bb1d3a64c5b Mon Sep 17 00:00:00 2001 From: Niklas Voss Date: Thu, 25 Mar 2021 09:55:26 +0100 Subject: [PATCH 1/6] Add basic support for adding/removing attributes to existing objects --- Makefile | 2 +- provider/provider.go | 3 +- provider/resource_ldap_object.go | 9 +- provider/resource_ldap_object_attributes.go | 243 ++++++++++++++++++++ 4 files changed, 250 insertions(+), 7 deletions(-) create mode 100644 provider/resource_ldap_object_attributes.go diff --git a/Makefile b/Makefile index 0f66524..6ec387f 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ HOSTNAME ?= github.com NAMESPACE ?= trevex NAME ?= ldap BINARY = terraform-provider-${NAME} -VERSION ?= 0.2 +VERSION ?= 0.5.0 OS_ARCH ?= darwin_amd64 default: install diff --git a/provider/provider.go b/provider/provider.go index 47a0cd0..d4ce16c 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -44,7 +44,8 @@ func New(version string) func() *schema.Provider { }, }, ResourcesMap: map[string]*schema.Resource{ - "ldap_object": resourceLDAPObject(), + "ldap_object": resourceLDAPObject(), + "ldap_object_attributes": resourceLDAPObjectAttributes(), }, DataSourcesMap: map[string]*schema.Resource{ "ldap_object": dataLDAPObject(), diff --git a/provider/resource_ldap_object.go b/provider/resource_ldap_object.go index a6ae84b..19ba733 100644 --- a/provider/resource_ldap_object.go +++ b/provider/resource_ldap_object.go @@ -7,7 +7,6 @@ import ( "context" "fmt" "hash/crc32" - "log" "strings" "github.com/pkg/errors" @@ -264,7 +263,7 @@ func resourceLDAPObjectUpdate(d *schema.ResourceData, meta interface{}) error { return err } } else { - warnLog("ldap_boject::update - didn't actually make changes to %q because there were no changes requested", dn) + warnLog("ldap_object::update - didn't actually make changes to %q because there were no changes requested", dn) } return resourceLDAPObjectRead(d, meta) } @@ -460,7 +459,7 @@ func computeAndAddDeltas(modify *ldap.ModifyRequest, os, ns *schema.Set, attribu // been added back, and there is no further value under the same // name among those that were untouched; this means that it has // been dropped and must go among the RemovedAttributes - log.Printf("[DEBUG} ldap_object::deltas - dropping attribute %q", k) + debugLog("ldap_object::deltas - dropping attribute %q", k) modify.Delete(k, []string{}) } else { ck.Add(k) @@ -486,7 +485,7 @@ func computeAndAddDeltas(modify *ldap.ModifyRequest, os, ns *schema.Set, attribu } } modify.Add(k, values) - log.Printf("[DEBUG} ldap_object::deltas - adding new attribute %q with values %v", k, values) + debugLog("ldap_object::deltas - adding new attribute %q with values %v", k, values) } else { ck.Add(k) } @@ -511,7 +510,7 @@ func computeAndAddDeltas(modify *ldap.ModifyRequest, os, ns *schema.Set, attribu } } modify.Replace(k, values) - log.Printf("[DEBUG} ldap_object::deltas - changing attribute %q with values %v", k, values) + debugLog("ldap_object::deltas - changing attribute %q with values %v", k, values) } return nil } diff --git a/provider/resource_ldap_object_attributes.go b/provider/resource_ldap_object_attributes.go new file mode 100644 index 0000000..38a55c3 --- /dev/null +++ b/provider/resource_ldap_object_attributes.go @@ -0,0 +1,243 @@ +package provider + +import ( + "github.com/go-ldap/ldap/v3" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceLDAPObjectAttributes() *schema.Resource { + return &schema.Resource{ + Create: resourceLDAPObjectAttributesCreate, + Read: resourceLDAPObjectAttributesRead, + Update: resourceLDAPObjectAttributesUpdate, + Delete: resourceLDAPObjectAttributesDelete, + + Schema: map[string]*schema.Schema{ + "dn": { + Type: schema.TypeString, + Description: "The Distinguished Name (DN) of the object, as the concatenation of its RDN (unique among siblings) and its parent's DN. The referenced object should exist to be able to add attributes.", + Required: true, + ForceNew: true, + }, + "attributes": { + Type: schema.TypeSet, + Description: "The map of attributes to add to the referenced object; each attribute can be multi-valued.", + Set: attributeHash, + MinItems: 0, + + Elem: &schema.Schema{ + Type: schema.TypeMap, + Description: "The list of values for a given attribute.", + MinItems: 1, + MaxItems: 1, + Elem: &schema.Schema{ + Type: schema.TypeString, + Description: "The individual value for the given attribute.", + }, + }, + Optional: true, + }, + }, + } +} + +func resourceLDAPObjectAttributesCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ldap.Conn) + dn := d.Get("dn").(string) + + debugLog("ldap_object_attributes::create - adding attributes to object %q", dn) + + request := ldap.NewModifyRequest(dn, []ldap.Control{}) + + // if there is a non empty list of attributes, loop though it and + // create a new map collecting attribute names and its value(s); we need to + // do this because we could not model the attributes as a map[string][]string + // due to an appareent limitation in HCL; we have a []map[string]string, so + // we loop through the list and accumulate values when they share the same + // key, then we use these as attributes in the LDAP client. + if v, ok := d.GetOk("attributes"); ok { + attributes := v.(*schema.Set).List() + if len(attributes) > 0 { + debugLog("ldap_object_attributes::create - object %q updated with %d additional attributes", dn, len(attributes)) + m := make(map[string][]string) + for _, attribute := range attributes { + debugLog("ldap_object_attributes::create - %q has attribute of type %T", dn, attribute) + // each map should only have one entry (see resource declaration) + for name, value := range attribute.(map[string]interface{}) { + debugLog("ldap_object_attributes::create - %q has attribute[%v] => %v (%T)", dn, name, value, value) + v := toAttributeValue(name, value.(string)) + m[name] = append(m[name], v) + } + } + // now loop through the map and add attributes with theys value(s) + for name, values := range m { + request.Add(name, values) + } + } + } + + err := client.Modify(request) + if err != nil { + return err + } + + debugLog("ldap_object_attributes::create - object %q updated with additional attributes", dn) + + d.SetId(dn) + return nil +} + +func resourceLDAPObjectAttributesRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ldap.Conn) + dn := d.Get("dn").(string) + + debugLog("ldap_object_attributes::read - looking for object %q", dn) + + // when searching by DN, you don't need t specify the base DN a search + // filter a "subtree" scope: just put the DN (i.e. the primary key) as the + // base DN with a "base object" scope, and the returned object will be the + // entry, if it exists + request := ldap.NewSearchRequest( + dn, + ldap.ScopeBaseObject, + ldap.NeverDerefAliases, + 0, + 0, + false, + "(objectclass=*)", + []string{"*"}, + nil, + ) + + sr, err := client.Search(request) + if err != nil { + if err, ok := err.(*ldap.Error); ok { + if err.ResultCode == 32 { // no such object + warnLog("ldap_object_attributes::read - object not found, removing %q from state because it no longer exists in LDAP", dn) + d.SetId("") + } + } + debugLog("ldap_object_attributes::read - lookup for %q returned an error %v", dn, err) + return err + } + + debugLog("ldap_object_attributes::read - query for %q returned %v", dn, sr) + + // Let's transform the attributes from LDAP into a set that we can intersect + // with our resources sets. + ldapSet := &schema.Set{ + F: attributeHash, + } + for _, attribute := range sr.Entries[0].Attributes { + debugLog("ldap_object_attributes::read - adding attribute %q to %q (%d values)", attribute.Name, dn, len(attribute.Values)) + // now add each value as an individual entry into the object, because + // we do not handle name => []values, and we have a set of maps each + // holding a single entry name => value; multiple maps may share the + // same key. + for _, value := range attribute.Values { + debugLog("ldap_object_attributes::read - for %q from ldap, setting %q => %q", dn, attribute.Name, value) + ldapSet.Add(map[string]interface{}{ + attribute.Name: value, + }) + } + } + + // We are both interested in the attributes before and after changes, so + // depending on what is available, let's compute the union + var ( + prevSet *schema.Set + nextSet *schema.Set + unionSet *schema.Set + ) + if d.HasChange("attributes") { + prev, next := d.GetChange("attributes") + prevSet = prev.(*schema.Set) + nextSet = next.(*schema.Set) + } else { + nextSet = d.Get("attributes").(*schema.Set) + } + if prevSet != nil { + unionSet = prevSet.Union(nextSet) + } else { + unionSet = nextSet + } + + // Now that we both have union of relevant terraform states and ldap, let's + // get the intersection and set it. + set := unionSet.Intersection(unionSet) + + // If the set is empty the attributes do not exist, yet. + if set.Len() == 0 { + d.SetId("") + return nil + } + + // The set contains values, let's set them and indicate that the object + // exists by setting the id as well. + if err := d.Set("attributes", set); err != nil { + warnLog("ldap_object_attributes::read - error setting attributes for %q : %v", dn, err) + return err + } + d.SetId(dn) + return nil +} + +func resourceLDAPObjectAttributesUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ldap.Conn) + dn := d.Get("dn").(string) + + debugLog("ldap_object_attributes::update - performing update on %q", dn) + + modify := ldap.NewModifyRequest(dn, []ldap.Control{}) + + if d.HasChange("attributes") { + o, n := d.GetChange("attributes") + debugLog("ldap_object_attributes::update - \n%s", printAttributes("old attributes map", o)) + debugLog("ldap_object_attributes::update - \n%s", printAttributes("new attributes map", n)) + + err := computeAndAddDeltas(modify, o.(*schema.Set), n.(*schema.Set), []string{}, []string{}) + if err != nil { + return err + } + } + + if len(modify.Changes) > 0 { + err := client.Modify(modify) + if err != nil { + errorLog("ldap_object_attributes::update - error modifying LDAP object %q with values %v", d.Id(), err) + return err + } + } else { + warnLog("ldap_object_attributes::update - didn't actually make changes to %q because there were no changes requested", dn) + } + return resourceLDAPObjectRead(d, meta) +} + +func resourceLDAPObjectAttributesDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ldap.Conn) + dn := d.Get("dn").(string) + + debugLog("ldap_object_attributes::delete - removing attributes from %q", dn) + + modify := ldap.NewModifyRequest(dn, []ldap.Control{}) + + err := computeAndAddDeltas(modify, d.Get("attributes").(*schema.Set), &schema.Set{ + F: attributeHash, + }, []string{}, []string{}) + if err != nil { + return err + } + + if len(modify.Changes) > 0 { + err := client.Modify(modify) + if err != nil { + errorLog("ldap_object_attributes::delete - error modifying LDAP object %q with values %v", d.Id(), err) + return err + } + } else { + warnLog("ldap_object_attributes::delete - didn't actually make changes to %q because there were no changes requested", dn) + } + + debugLog("ldap_object::delete - %q removed", dn) + return nil +} From fd97ce22d0829d944ce78fe329172587d81c444a Mon Sep 17 00:00:00 2001 From: Niklas Voss Date: Thu, 25 Mar 2021 13:18:03 +0100 Subject: [PATCH 2/6] Correct minor typos --- provider/resource_ldap_object.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/provider/resource_ldap_object.go b/provider/resource_ldap_object.go index 19ba733..4a7fbab 100644 --- a/provider/resource_ldap_object.go +++ b/provider/resource_ldap_object.go @@ -81,7 +81,7 @@ func resourceLDAPObject() *schema.Resource { func resourceLDAPObjectImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { dn := d.Id() - debugLog("Goign to import dn %q", dn) + debugLog("Going to import dn %q", dn) d.Set("dn", dn) err := resourceLDAPObjectRead(d, meta) return []*schema.ResourceData{d}, errors.Wrap(err, "Reading ldap object") @@ -91,7 +91,7 @@ func resourceLDAPObjectExists(d *schema.ResourceData, meta interface{}) (b bool, l := meta.(*ldap.Conn) dn := d.Get("dn").(string) - debugLog("[DEBUG] ldap_object::exists - checking if %q exists", dn) + debugLog("ldap_object::exists - checking if %q exists", dn) // search by primary key (that is, set the DN as base DN and use a "base // object" scope); no attributes are retrieved since we are onĂ²y checking From d4b0ef7f225102efb5ce8176bf372971760de9fb Mon Sep 17 00:00:00 2001 From: Niklas Voss Date: Thu, 25 Mar 2021 13:18:28 +0100 Subject: [PATCH 3/6] Use custom delta function for attributes to only modify resources. --- provider/resource_ldap_object_attributes.go | 72 +++++++++++++++++++-- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/provider/resource_ldap_object_attributes.go b/provider/resource_ldap_object_attributes.go index 38a55c3..c7e2409 100644 --- a/provider/resource_ldap_object_attributes.go +++ b/provider/resource_ldap_object_attributes.go @@ -1,8 +1,12 @@ package provider import ( + "fmt" + "strings" + "github.com/go-ldap/ldap/v3" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/trevex/terraform-provider-ldap/util" ) func resourceLDAPObjectAttributes() *schema.Resource { @@ -130,6 +134,14 @@ func resourceLDAPObjectAttributesRead(d *schema.ResourceData, meta interface{}) } for _, attribute := range sr.Entries[0].Attributes { debugLog("ldap_object_attributes::read - adding attribute %q to %q (%d values)", attribute.Name, dn, len(attribute.Values)) + if len(attribute.Values) == 1 { + // we don't treat the RDN as an ordinary attribute + a := fmt.Sprintf("%s=%s", attribute.Name, attribute.Values[0]) + if strings.HasPrefix(dn, a) { + debugLog("ldap_object_attributes::read - skipping RDN %q of %q", a, dn) + continue + } + } // now add each value as an individual entry into the object, because // we do not handle name => []values, and we have a set of maps each // holding a single entry name => value; multiple maps may share the @@ -161,10 +173,12 @@ func resourceLDAPObjectAttributesRead(d *schema.ResourceData, meta interface{}) } else { unionSet = nextSet } + debugLog("ldap_object_attributes::read - union of %q => %v", dn, unionSet.List()) // Now that we both have union of relevant terraform states and ldap, let's // get the intersection and set it. - set := unionSet.Intersection(unionSet) + set := unionSet.Intersection(ldapSet) + debugLog("ldap_object_attributes::read - intersection with ldap of %q => %v", dn, set.List()) // If the set is empty the attributes do not exist, yet. if set.Len() == 0 { @@ -195,7 +209,7 @@ func resourceLDAPObjectAttributesUpdate(d *schema.ResourceData, meta interface{} debugLog("ldap_object_attributes::update - \n%s", printAttributes("old attributes map", o)) debugLog("ldap_object_attributes::update - \n%s", printAttributes("new attributes map", n)) - err := computeAndAddDeltas(modify, o.(*schema.Set), n.(*schema.Set), []string{}, []string{}) + err := computeAndAddAttributeDeltas(modify, o.(*schema.Set), n.(*schema.Set)) if err != nil { return err } @@ -210,7 +224,7 @@ func resourceLDAPObjectAttributesUpdate(d *schema.ResourceData, meta interface{} } else { warnLog("ldap_object_attributes::update - didn't actually make changes to %q because there were no changes requested", dn) } - return resourceLDAPObjectRead(d, meta) + return resourceLDAPObjectAttributesRead(d, meta) } func resourceLDAPObjectAttributesDelete(d *schema.ResourceData, meta interface{}) error { @@ -221,9 +235,9 @@ func resourceLDAPObjectAttributesDelete(d *schema.ResourceData, meta interface{} modify := ldap.NewModifyRequest(dn, []ldap.Control{}) - err := computeAndAddDeltas(modify, d.Get("attributes").(*schema.Set), &schema.Set{ + err := computeAndAddAttributeDeltas(modify, d.Get("attributes").(*schema.Set), &schema.Set{ F: attributeHash, - }, []string{}, []string{}) + }) if err != nil { return err } @@ -241,3 +255,51 @@ func resourceLDAPObjectAttributesDelete(d *schema.ResourceData, meta interface{} debugLog("ldap_object::delete - %q removed", dn) return nil } + +func computeAndAddAttributeDeltas(modify *ldap.ModifyRequest, os, ns *schema.Set) error { + ra := os.Difference(ns) // removed attributes + rk := util.NewSet() // names of removed attributes + for _, v := range ra.List() { + for k := range v.(map[string]interface{}) { + rk.Add(k) + } + } + + aa := ns.Difference(os) // added attributes + ak := util.NewSet() // names of added attributes + for _, v := range aa.List() { + for k := range v.(map[string]interface{}) { + ak.Add(k) + } + } + // loop over remove attributes' names + for _, k := range rk.List() { + values := []string{} + for _, m := range ra.List() { + for mk, mv := range m.(map[string]interface{}) { + if k == mk { + v := toAttributeValue(k, mv.(string)) + values = append(values, v) + } + } + } + modify.Delete(k, values) + debugLog("ldap_object_attributes::deltas - removing attribute %q with values %v", k, values) + } + + for _, k := range ak.List() { + values := []string{} + for _, m := range aa.List() { + for mk, mv := range m.(map[string]interface{}) { + if k == mk { + v := toAttributeValue(k, mv.(string)) + values = append(values, v) + } + } + } + modify.Add(k, values) + debugLog("ldap_object_attributes::deltas - adding new attribute %q with values %v", k, values) + } + + return nil +} From b9e946f046452eab1b7d822e8d4e28c9a2d16b85 Mon Sep 17 00:00:00 2001 From: Niklas Voss Date: Thu, 25 Mar 2021 16:37:42 +0100 Subject: [PATCH 4/6] Additional debug logs and minor refactor of variable names --- provider/resource_ldap_object_attributes.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/provider/resource_ldap_object_attributes.go b/provider/resource_ldap_object_attributes.go index c7e2409..fe23d8e 100644 --- a/provider/resource_ldap_object_attributes.go +++ b/provider/resource_ldap_object_attributes.go @@ -157,21 +157,23 @@ func resourceLDAPObjectAttributesRead(d *schema.ResourceData, meta interface{}) // We are both interested in the attributes before and after changes, so // depending on what is available, let's compute the union var ( - prevSet *schema.Set - nextSet *schema.Set + oldSet *schema.Set + newSet *schema.Set unionSet *schema.Set ) if d.HasChange("attributes") { prev, next := d.GetChange("attributes") - prevSet = prev.(*schema.Set) - nextSet = next.(*schema.Set) + oldSet = prev.(*schema.Set) + newSet = next.(*schema.Set) } else { - nextSet = d.Get("attributes").(*schema.Set) + newSet = d.Get("attributes").(*schema.Set) } - if prevSet != nil { - unionSet = prevSet.Union(nextSet) + debugLog("ldap_object_attributes::read - newSet of %q => %v", dn, newSet.List()) + if oldSet != nil { + debugLog("ldap_object_attributes::read - oldSet of %q => %v", dn, oldSet.List()) + unionSet = oldSet.Union(newSet) } else { - unionSet = nextSet + unionSet = newSet } debugLog("ldap_object_attributes::read - union of %q => %v", dn, unionSet.List()) From 8bafc38630943aec4b43cdbb7a4a3c74d79a7f96 Mon Sep 17 00:00:00 2001 From: Niklas Voss Date: Fri, 26 Mar 2021 12:05:59 +0100 Subject: [PATCH 5/6] Update terraform sdk and use read at the end of create to verify state --- go.mod | 2 +- go.sum | 30 +++++++++++++++++++++ provider/resource_ldap_object_attributes.go | 4 +-- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 045487d..101eea4 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.15 require ( github.com/go-ldap/ldap/v3 v3.2.4 - github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.4 + github.com/hashicorp/terraform-plugin-sdk/v2 v2.5.0 github.com/pkg/errors v0.8.1 golang.org/x/text v0.3.3 ) diff --git a/go.sum b/go.sum index 27821ce..c0beb80 100644 --- a/go.sum +++ b/go.sum @@ -39,6 +39,7 @@ github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXva github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/andybalholm/crlf v0.0.0-20171020200849-670099aa064f/go.mod h1:k8feO4+kXDxro6ErPXBRTJ/ro2mf0SsFG8s7doP9kJE= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/apparentlymart/go-cidr v1.0.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= @@ -69,6 +70,7 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= @@ -120,6 +122,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -145,10 +149,15 @@ github.com/hashicorp/go-getter v1.5.0/go.mod h1:a7z7NPPfNQpJWcn4rSWFtdrSldqLdLPE github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.15.0 h1:qMuK0wxsoW4D0ddCCYwPSTm4KQv1X1ke3WmPWZ0Mvsk= +github.com/hashicorp/go-hclog v0.15.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-plugin v1.3.0 h1:4d/wJojzvHV1I4i/rrjVaeuyxWrLzDE1mDCyDy8fXS8= github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= +github.com/hashicorp/go-plugin v1.4.0 h1:b0O7rs5uiJ99Iu9HugEzsM67afboErkHUWddUSpUO3A= +github.com/hashicorp/go-plugin v1.4.0/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= @@ -162,9 +171,15 @@ github.com/hashicorp/hcl/v2 v2.3.0 h1:iRly8YaMwTBAKhn1Ybk7VSdzbnopghktCD031P8ggU github.com/hashicorp/hcl/v2 v2.3.0/go.mod h1:d+FwDBbOLvpAM3Z6J7gPj/VoAGkNe/gm352ZhjJ/Zv8= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/terraform-exec v0.10.0/go.mod h1:tOT8j1J8rP05bZBGWXfMyU3HkLi1LWyqL3Bzsc3CJjo= +github.com/hashicorp/terraform-exec v0.13.0/go.mod h1:SGhto91bVRlgXQWcJ5znSz+29UZIa8kpBbkGwQ+g9E8= github.com/hashicorp/terraform-json v0.5.0/go.mod h1:eAbqb4w0pSlRmdvl8fOyHAi/+8jnkVYN28gJkSJrLhU= +github.com/hashicorp/terraform-json v0.8.0/go.mod h1:3defM4kkMfttwiE7VakJDwCd4R+umhSQnvJwORXbprE= +github.com/hashicorp/terraform-plugin-go v0.2.1 h1:EW/R8bB2Zbkjmugzsy1d27yS8/0454b3MtYHkzOknqA= +github.com/hashicorp/terraform-plugin-go v0.2.1/go.mod h1:10V6F3taeDWVAoLlkmArKttR3IULlRWFAGtQIQTIDr4= github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.4 h1:GYkUL3zjrZgig9Gm+/61+YglzESJxXRDMp7qhJsh4j0= github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.4/go.mod h1:GP0lmw4Y+XV1OfTmi/hK75t5KWGGzoOzEgUBPGZ6Wq4= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.5.0 h1:4EHNOAjwiYCeBxY16rt2KwyRNNVsCaVO3kWBbiXfYM0= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.5.0/go.mod h1:z+cMZ0iswzZOahBJ3XmNWgWkVnAd2bl8g+FhyyuPDH4= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= @@ -191,8 +206,13 @@ github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LE github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mitchellh/cli v1.1.1/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= @@ -213,6 +233,7 @@ github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY7 github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce/go.mod h1:uFMI8w+ref4v2r9jz+c9i1IfIttS/OkmLfrk1jne5hs= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -231,11 +252,14 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack v4.0.1+incompatible h1:RMF1enSPeKTlXrXdOcqjFUElywVZjjC6pqse21bKbEU= github.com/vmihailenco/msgpack v4.0.1+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= +github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -243,6 +267,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= github.com/zclconf/go-cty v1.2.1 h1:vGMsygfmeCl4Xb6OA5U5XVAaQZ69FvoG7X2jUtQujb8= github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= +github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -333,6 +358,7 @@ golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -342,6 +368,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -470,6 +497,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0= +google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -492,6 +521,7 @@ gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/provider/resource_ldap_object_attributes.go b/provider/resource_ldap_object_attributes.go index fe23d8e..713e340 100644 --- a/provider/resource_ldap_object_attributes.go +++ b/provider/resource_ldap_object_attributes.go @@ -87,8 +87,7 @@ func resourceLDAPObjectAttributesCreate(d *schema.ResourceData, meta interface{} debugLog("ldap_object_attributes::create - object %q updated with additional attributes", dn) - d.SetId(dn) - return nil + return resourceLDAPObjectAttributesRead(d, meta) } func resourceLDAPObjectAttributesRead(d *schema.ResourceData, meta interface{}) error { @@ -153,6 +152,7 @@ func resourceLDAPObjectAttributesRead(d *schema.ResourceData, meta interface{}) }) } } + debugLog("ldap_object_attributes::read - attributes from ldap of %q => %v", dn, ldapSet.List()) // We are both interested in the attributes before and after changes, so // depending on what is available, let's compute the union From 7df64ef4b952715e208d661de79b8e29163f688f Mon Sep 17 00:00:00 2001 From: Niklas Voss Date: Fri, 26 Mar 2021 12:08:51 +0100 Subject: [PATCH 6/6] Add description to ldap_object_attributes --- provider/resource_ldap_object_attributes.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/provider/resource_ldap_object_attributes.go b/provider/resource_ldap_object_attributes.go index 713e340..9a44526 100644 --- a/provider/resource_ldap_object_attributes.go +++ b/provider/resource_ldap_object_attributes.go @@ -16,6 +16,8 @@ func resourceLDAPObjectAttributes() *schema.Resource { Update: resourceLDAPObjectAttributesUpdate, Delete: resourceLDAPObjectAttributesDelete, + Description: "The `ldap_object_attributes`-resource owns only specific attributes of an object. In case of multi-valued attributes the resource only owns the values defined by the resource and all pre-existing ones or ones added by other means are left in-tact.", + Schema: map[string]*schema.Schema{ "dn": { Type: schema.TypeString,