Skip to content

Commit

Permalink
feat: WIP download service users
Browse files Browse the repository at this point in the history
  • Loading branch information
arthurpitman committed Jan 22, 2025
1 parent 7603f3b commit 7d029ee
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 9 deletions.
16 changes: 12 additions & 4 deletions pkg/account/downloader/downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ package downloader
import (
"context"
"fmt"

"github.com/go-logr/logr"

"github.com/dynatrace/dynatrace-configuration-as-code-core/api/clients/accounts"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/internal/log"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/account"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/account/downloader/internal/http"
"github.com/go-logr/logr"
)

type Downloader struct {
Expand Down Expand Up @@ -61,10 +63,16 @@ func (a *Downloader) DownloadResources(ctx context.Context) (*account.Resources,
return nil, fmt.Errorf("failed to fetch users: %w", err)
}

serviceUsers, err := a.serviceUsers(ctx, groups)
if err != nil {
return nil, fmt.Errorf("failed to fetch service users: %w", err)
}

r := account.Resources{
Users: users.asAccountUsers(),
Groups: groups.asAccountGroups(),
Policies: policies.asAccountPolicies(),
Users: users.asAccountUsers(),
ServiceUsers: serviceUsers.asAccountServiceUsers(),
Groups: groups.asAccountGroups(),
Policies: policies.asAccountPolicies(),
}

return &r, nil
Expand Down
13 changes: 8 additions & 5 deletions pkg/account/downloader/downloader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,18 @@ package downloader_test

import (
"context"
"testing"

"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"

accountmanagement "github.com/dynatrace/dynatrace-configuration-as-code-core/gen/account_management"
stringutils "github.com/dynatrace/dynatrace-configuration-as-code/v2/internal/strings"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/account"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/account/downloader"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/account/downloader/internal/http"
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
"testing"
)

func TestDownloader_DownloadConfiguration(t *testing.T) {
Expand Down Expand Up @@ -579,6 +581,7 @@ func newMockDownloader(d mockData, t *testing.T) *downloader.Downloader {
client.EXPECT().GetGroups(gomock.Any(), d.ai.AccountUUID).Return(d.groups, d.groupsError).MinTimes(0).MaxTimes(1)
client.EXPECT().GetUsers(gomock.Any(), d.ai.AccountUUID).Return(d.users, d.usersError).MinTimes(0).MaxTimes(1)
client.EXPECT().GetGroupsForUser(gomock.Any(), userEmail(d.users), d.ai.AccountUUID).Return(d.userGroups, d.groupsForUserError).AnyTimes()
client.EXPECT().GetServiceUsers(gomock.Any(), d.ai.AccountUUID).Return(d.userGroups, d.groupsForUserError).AnyTimes()

return downloader.New4Test(d.ai, client)
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/account/downloader/http_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ package downloader

import (
"context"

accountmanagement "github.com/dynatrace/dynatrace-configuration-as-code-core/gen/account_management"
)

//go:generate mockgen -source http_client.go -package=http -destination=internal/http/client_mock.go
type httpClient interface {
GetUsers(ctx context.Context, accountUUID string) ([]accountmanagement.UsersDto, error)
GetServiceUsers(ctx context.Context, accountUUID string) ([]accountmanagement.ExternalServiceUserDto, error)
GetGroupsForUser(ctx context.Context, userEmail string, accountUUID string) (*accountmanagement.GroupUserDto, error)
GetPolicies(ctx context.Context, account string) ([]accountmanagement.PolicyOverview, error)
GetPolicyDefinition(ctx context.Context, dto accountmanagement.PolicyOverview) (*accountmanagement.LevelPolicyDto, error)
Expand Down
23 changes: 23 additions & 0 deletions pkg/account/downloader/internal/http/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,29 @@ func (c *Client) GetUsers(ctx context.Context, accountUUID string) ([]accountman
return r.Items, nil
}

func (c *Client) GetServiceUsers(ctx context.Context, accountUUID string) ([]accountmanagement.ExternalServiceUserDto, error) {
serviceUsers := []accountmanagement.ExternalServiceUserDto{}
const pageSize = 10
for page := 1; ; page++ {
r, resp, err := c.ServiceUserManagementAPI.GetServiceUsersFromAccount(ctx, accountUUID).Page(float32(page)).PageSize(pageSize).Execute()
defer closeResponseBody(resp)
if err = getErrorMessageFromResponse(resp, err); err != nil {
return nil, err
}
if r == nil {
return nil, errors.New("the received data are empty")
}

serviceUsers = append(serviceUsers, r.Results...)

if r.NextPageKey == nil {

Check failure on line 59 in pkg/account/downloader/internal/http/client.go

View workflow job for this annotation

GitHub Actions / Verify

invalid operation: r.NextPageKey == nil (mismatched types string and untyped nil)

Check failure on line 59 in pkg/account/downloader/internal/http/client.go

View workflow job for this annotation

GitHub Actions / Build and Test

invalid operation: r.NextPageKey == nil (mismatched types string and untyped nil)
break
}
}

return serviceUsers, nil
}

func (c *Client) GetGroupsForUser(ctx context.Context, userEmail string, accountUUID string) (*accountmanagement.GroupUserDto, error) {
r, resp, err := c.UserManagementAPI.GetUserGroups(ctx, accountUUID, userEmail).Execute()
defer closeResponseBody(resp)
Expand Down
80 changes: 80 additions & 0 deletions pkg/account/downloader/service_users.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* @license
* Copyright 2023 Dynatrace LLC
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package downloader

import (
"context"
"fmt"

accountmanagement "github.com/dynatrace/dynatrace-configuration-as-code-core/gen/account_management"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/internal/log"
"github.com/dynatrace/dynatrace-configuration-as-code/v2/pkg/account"
)

type (
ServiceUsers []serviceUser

serviceUser struct {
serviceUser *account.ServiceUser
dto *accountmanagement.ExternalServiceUserDto
dtoGroups *accountmanagement.GroupUserDto
}
)

func (a *Downloader) serviceUsers(ctx context.Context, groups Groups) (ServiceUsers, error) {
log.WithCtxFields(ctx).Info("Downloading service users")
dtos, err := a.httpClient.GetServiceUsers(ctx, a.accountInfo.AccountUUID)
if err != nil {
return nil, fmt.Errorf("failed to get a list of service users for account %q from DT: %w", a.accountInfo, err)
}

retVal := make(ServiceUsers, 0, len(dtos))
for _, dto := range dtos {
log.WithCtxFields(ctx).Debug("Downloading details for user %q", dto.Name)
dtoGroups, err := a.httpClient.GetGroupsForUser(ctx, dto.Email, a.accountInfo.AccountUUID)
if err != nil {
return nil, fmt.Errorf("failed to get a list of bind groups for service user %q: %w", dto.Name, err)
}
if dtoGroups == nil {
return nil, fmt.Errorf("failed to get a list of bind groups for the service user %q", dto.Name)
}

su := &account.ServiceUser{
Name: dto.Name,
OriginObjectID: dtoGroups.Uid,
Description: dto.Description,
Groups: groups.refFromDTOs(dtoGroups.Groups),
}

retVal = append(retVal, serviceUser{
serviceUser: su,
dto: &dto,
dtoGroups: dtoGroups,
})
}

log.WithCtxFields(ctx).Info("Fetched %d service users", len(retVal))
return retVal, nil
}

func (sus ServiceUsers) asAccountServiceUsers() map[account.ServiceUserId]account.ServiceUser {
retVal := make(map[account.ServiceUserId]account.ServiceUser, len(sus))
for _, su := range sus {
retVal[su.serviceUser.Name] = *su.serviceUser
}
return retVal
}

0 comments on commit 7d029ee

Please sign in to comment.