Skip to content

Commit 93bad0d

Browse files
authored
org_member: only invite if user not present (#115)
fixes #114 Signed-off-by: Nick Santos <nick.santos@docker.com>
1 parent f20ff83 commit 93bad0d

File tree

2 files changed

+41
-28
lines changed

2 files changed

+41
-28
lines changed

internal/provider/data_source_repository_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func TestAccRepositoryDataSource(t *testing.T) {
3131
{
3232
Config: testAccExampleDataSourceConfig,
3333
Check: resource.ComposeAggregateTestCheckFunc(
34-
resource.TestCheckResourceAttr("data.docker_hub_repository.test", "id", "ryanhristovski/data-source-example"),
34+
resource.TestCheckResourceAttr("data.docker_hub_repository.test", "id", "dockerterraform/docker-terraform-repo-demo"),
3535
resource.TestCheckResourceAttr("data.docker_hub_repository.test", "immutable_tags_settings.enabled", "false"),
3636
),
3737
},
@@ -41,7 +41,7 @@ func TestAccRepositoryDataSource(t *testing.T) {
4141

4242
const testAccExampleDataSourceConfig = `
4343
data "docker_hub_repository" "test" {
44-
namespace = "ryanhristovski"
45-
name = "data-source-example"
44+
namespace = "dockerterraform"
45+
name = "docker-terraform-repo-demo"
4646
}
4747
`

internal/provider/resource_org_member.go

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -177,32 +177,36 @@ func (r *OrgMemberResource) Create(ctx context.Context, req resource.CreateReque
177177
return
178178
}
179179

180-
inviteResp, err := r.client.InviteOrgMember(ctx, data.OrgName.ValueString(), data.Role.ValueString(), []string{invitee}, false)
180+
current, found, err := r.orgMember(ctx, data.OrgName.ValueString(), invitee)
181181
if err != nil {
182-
errMsg := fmt.Sprintf("Unable to create org_member resource: %v", err)
183-
resp.Diagnostics.AddError("Error Creating Resource", errMsg)
182+
resp.Diagnostics.AddError("Error Checking Existing Member", err.Error())
184183
return
185184
}
186185

187-
if len(inviteResp.OrgInvitees) == 0 {
188-
errMsg := "No invitees were returned from the Docker Hub API."
189-
resp.Diagnostics.AddError("Invite Failed", errMsg)
190-
return
191-
}
192-
193-
invite := inviteResp.OrgInvitees[0]
194-
if invite.Invite.ID != "" {
195-
data.InviteID = types.StringValue(invite.Invite.ID)
186+
if found {
187+
// Set computed fields.
188+
data.InviteID = current.InviteID
189+
data.Email = current.Email
196190
} else {
197-
// If the invite is in a pending state, then InviteOrgMember does not return
198-
// the invite ID. We need to get the invite ID from the org invites.
199-
member, err := r.orgMember(ctx, data.OrgName.ValueString(), invitee)
191+
// If the member is not found, invite them now.
192+
inviteResp, err := r.client.InviteOrgMember(ctx,
193+
data.OrgName.ValueString(), data.Role.ValueString(), []string{invitee}, false)
200194
if err != nil {
201-
errMsg := fmt.Sprintf("Could not resolve member status: %v", err)
195+
errMsg := fmt.Sprintf("Unable to create org_member resource: %v", err)
202196
resp.Diagnostics.AddError("Error Creating Resource", errMsg)
203197
return
204198
}
205-
data.InviteID = member.InviteID
199+
200+
if len(inviteResp.OrgInvitees) == 0 {
201+
errMsg := "No invitees were returned from the Docker Hub API."
202+
resp.Diagnostics.AddError("Invite Failed", errMsg)
203+
return
204+
}
205+
206+
invite := inviteResp.OrgInvitees[0]
207+
if invite.Invite.ID != "" {
208+
data.InviteID = types.StringValue(invite.Invite.ID)
209+
}
206210
}
207211

208212
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
@@ -225,11 +229,15 @@ func (r *OrgMemberResource) Read(ctx context.Context, req resource.ReadRequest,
225229
return
226230
}
227231

228-
data, err := r.orgMember(ctx, state.OrgName.ValueString(), invitee)
232+
data, found, err := r.orgMember(ctx, state.OrgName.ValueString(), invitee)
229233
if err != nil {
230234
resp.Diagnostics.AddError("Error Reading Resource", err.Error())
231235
return
232236
}
237+
if !found {
238+
resp.Diagnostics.AddError("Resource Not Found",
239+
fmt.Sprintf("Member not found in %s: %s", state.OrgName.ValueString(), invitee))
240+
}
233241

234242
if data.Role.ValueString() == "" {
235243
data.Role = state.Role
@@ -242,7 +250,10 @@ func (r *OrgMemberResource) Read(ctx context.Context, req resource.ReadRequest,
242250
}
243251
}
244252

245-
// TODO: setup update
253+
// NOTE(nicks): currently, we treat all fields as immutable,
254+
// so in theory update should never happen.
255+
//
256+
// Future work: update the provider to allow role changes.
246257
func (r *OrgMemberResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
247258
return
248259
}
@@ -308,7 +319,9 @@ func (r *OrgMemberResource) ImportState(ctx context.Context, req resource.Import
308319
//
309320
// Our org_member represents both invited and accepted members, so
310321
// we need to merge the results from both endpoints.
311-
func (r *OrgMemberResource) orgMember(ctx context.Context, orgName string, userName string) (OrgMemberResourceModel, error) {
322+
//
323+
// Returns true if the member was found, false if not found.
324+
func (r *OrgMemberResource) orgMember(ctx context.Context, orgName string, userName string) (OrgMemberResourceModel, bool, error) {
312325
r.mu.Lock()
313326
defer r.mu.Unlock()
314327

@@ -317,7 +330,7 @@ func (r *OrgMemberResource) orgMember(ctx context.Context, orgName string, userN
317330
var err error
318331
members, err = r.client.ListOrgMembers(ctx, orgName)
319332
if err != nil {
320-
return OrgMemberResourceModel{}, err
333+
return OrgMemberResourceModel{}, false, err
321334
}
322335
r.orgMembers[orgName] = members
323336
}
@@ -329,7 +342,7 @@ func (r *OrgMemberResource) orgMember(ctx context.Context, orgName string, userN
329342
UserName: types.StringValue(member.Username),
330343
Role: types.StringValue(strings.ToLower(member.Role)),
331344
Email: types.StringValue(member.Email),
332-
}, nil
345+
}, true, nil
333346
}
334347
}
335348

@@ -338,7 +351,7 @@ func (r *OrgMemberResource) orgMember(ctx context.Context, orgName string, userN
338351
var err error
339352
invites, err = r.client.ListOrgInvites(ctx, orgName)
340353
if err != nil {
341-
return OrgMemberResourceModel{}, err
354+
return OrgMemberResourceModel{}, false, err
342355
}
343356
r.orgInvites[orgName] = invites
344357
}
@@ -354,9 +367,9 @@ func (r *OrgMemberResource) orgMember(ctx context.Context, orgName string, userN
354367
} else {
355368
result.UserName = types.StringValue(userName)
356369
}
357-
return result, nil
370+
return result, true, nil
358371
}
359372
}
360373

361-
return OrgMemberResourceModel{}, fmt.Errorf("member not found in org. Org: %s, User: %s", orgName, userName)
374+
return OrgMemberResourceModel{}, false, nil
362375
}

0 commit comments

Comments
 (0)