Skip to content

Commit

Permalink
Merge pull request #283 from ekristen/issue-279
Browse files Browse the repository at this point in the history
feat(iam-role): add new properties (name, path, dates and more)
  • Loading branch information
ekristen authored Sep 11, 2024
2 parents e90bde7 + b0776a8 commit ba4a553
Show file tree
Hide file tree
Showing 11 changed files with 532 additions and 178 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package resources

import (
"context"

"fmt"
"time"

Expand Down Expand Up @@ -32,14 +31,22 @@ func init() {
})
}

type IAMInstanceProfileRoleLister struct{}
type IAMInstanceProfileRoleLister struct {
mockSvc iamiface.IAMAPI
}

func (l *IAMInstanceProfileRoleLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) {
opts := o.(*nuke.ListerOpts)
resources := make([]resource.Resource, 0)

var svc iamiface.IAMAPI
if l.mockSvc != nil {
svc = l.mockSvc
} else {
svc = iam.New(opts.Session)
}

svc := iam.New(opts.Session)
params := &iam.ListInstanceProfilesInput{}
resources := make([]resource.Resource, 0)

for {
resp, err := svc.ListInstanceProfiles(params)
Expand Down Expand Up @@ -111,7 +118,7 @@ func (e *IAMInstanceProfileRole) Properties() types.Properties {
Set("InstanceRole", e.role.RoleName).
Set("role:Path", e.role.Path).
Set("role:CreateDate", e.role.CreateDate.Format(time.RFC3339)).
Set("role:LastUsedDate", getLastUsedDate(e.role, time.RFC3339))
Set("role:LastUsedDate", getLastUsedDate(e.role))

for _, tagValue := range e.role.Tags {
properties.SetTagWithPrefix("role", tagValue.Key, tagValue.Value)
Expand Down
96 changes: 96 additions & 0 deletions resources/iam-instance-profile-role_mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,72 @@ package resources
import (
"context"
"testing"
"time"

"github.com/golang/mock/gomock"
"github.com/gotidy/ptr"
"github.com/stretchr/testify/assert"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/iam"

"github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface"
"github.com/ekristen/aws-nuke/v3/pkg/nuke"
)

func Test_Mock_IAMInstanceProfileRole_List(t *testing.T) {
a := assert.New(t)
ctrl := gomock.NewController(t)
defer ctrl.Finish()

mockIAM := mock_iamiface.NewMockIAMAPI(ctrl)

iamInstanceProfileRole := IAMInstanceProfileRole{
svc: mockIAM,
role: &iam.Role{
RoleName: ptr.String("role:foobar"),
},
profile: &iam.InstanceProfile{
Arn: ptr.String("arn:aws:iam::123456789012:instance-profile/profile:foobar"),
InstanceProfileName: ptr.String("profile:foobar"),
CreateDate: ptr.Time(time.Now()),
Roles: []*iam.Role{
{
Arn: ptr.String("arn:aws:iam::123456789012:role/role:foobar"),
RoleName: ptr.String("role:foobar"),
},
},
},
}

mockIAM.EXPECT().ListInstanceProfiles(gomock.Any()).Return(&iam.ListInstanceProfilesOutput{
InstanceProfiles: []*iam.InstanceProfile{
iamInstanceProfileRole.profile,
},
IsTruncated: ptr.Bool(false),
}, nil)

mockIAM.EXPECT().GetInstanceProfile(&iam.GetInstanceProfileInput{
InstanceProfileName: iamInstanceProfileRole.profile.InstanceProfileName,
}).Return(&iam.GetInstanceProfileOutput{
InstanceProfile: iamInstanceProfileRole.profile,
}, nil)

lister := IAMInstanceProfileRoleLister{
mockSvc: mockIAM,
}

resources, err := lister.List(context.TODO(), &nuke.ListerOpts{
Region: &nuke.Region{
Name: "us-east-2",
},
Session: session.Must(session.NewSession()),
})
a.Nil(err)
a.Len(resources, 1)
}

func Test_Mock_IAMInstanceProfileRole_Remove(t *testing.T) {
a := assert.New(t)
ctrl := gomock.NewController(t)
Expand All @@ -38,3 +94,43 @@ func Test_Mock_IAMInstanceProfileRole_Remove(t *testing.T) {
err := iamInstanceProfileRole.Remove(context.TODO())
a.Nil(err)
}

func Test_Mock_IAMInstanceProfileRole_Properties(t *testing.T) {
a := assert.New(t)

now := time.Now()

iamInstanceProfileRole := IAMInstanceProfileRole{
role: &iam.Role{
Arn: ptr.String("arn:aws:iam::123456789012:role/role:foobar"),
RoleName: ptr.String("role:foobar"),
Path: ptr.String("/"),
CreateDate: ptr.Time(now),
Tags: []*iam.Tag{
{
Key: ptr.String("Name"),
Value: ptr.String("bar"),
},
},
},
profile: &iam.InstanceProfile{
InstanceProfileName: ptr.String("profile:foobar"),
Tags: []*iam.Tag{
{
Key: ptr.String("Name"),
Value: ptr.String("foo"),
},
},
},
}

props := iamInstanceProfileRole.Properties()
a.Equal("profile:foobar", props.Get("InstanceProfile"))
a.Equal("role:foobar", props.Get("InstanceRole"))
a.Equal("/", props.Get("role:Path"))
a.Equal(now.Format(time.RFC3339), props.Get("role:CreateDate"))
a.Equal("foo", props.Get("tag:Name"))
a.Equal("bar", props.Get("tag:role:Name"))

a.Equal("profile:foobar -> role:foobar", iamInstanceProfileRole.String())
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,22 @@ func init() {
})
}

type IAMInstanceProfileLister struct{}
type IAMInstanceProfileLister struct {
mockSvc iamiface.IAMAPI
}

func (l *IAMInstanceProfileLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) {
opts := o.(*nuke.ListerOpts)
resources := make([]resource.Resource, 0)

var svc iamiface.IAMAPI
if l.mockSvc != nil {
svc = l.mockSvc
} else {
svc = iam.New(opts.Session)
}

svc := iam.New(opts.Session)
params := &iam.ListInstanceProfilesInput{}
resources := make([]resource.Resource, 0)

for {
resp, err := svc.ListInstanceProfiles(params)
Expand All @@ -55,10 +63,10 @@ func (l *IAMInstanceProfileLister) List(_ context.Context, o interface{}) ([]res
}

resources = append(resources, &IAMInstanceProfile{
svc: svc,
name: *out.InstanceProfileName,
path: *profile.Path,
profile: profile,
svc: svc,
Name: out.InstanceProfileName,
Path: profile.Path,
Tags: profile.Tags,
})
}

Expand All @@ -72,24 +80,16 @@ func (l *IAMInstanceProfileLister) List(_ context.Context, o interface{}) ([]res
return resources, nil
}

func GetIAMInstanceProfile(svc *iam.IAM, instanceProfileName *string) (*iam.InstanceProfile, error) {
params := &iam.GetInstanceProfileInput{
InstanceProfileName: instanceProfileName,
}
resp, err := svc.GetInstanceProfile(params)
return resp.InstanceProfile, err
}

type IAMInstanceProfile struct {
svc iamiface.IAMAPI
name string
path string
profile *iam.InstanceProfile
svc iamiface.IAMAPI
Name *string
Path *string
Tags []*iam.Tag
}

func (e *IAMInstanceProfile) Remove(_ context.Context) error {
_, err := e.svc.DeleteInstanceProfile(&iam.DeleteInstanceProfileInput{
InstanceProfileName: &e.name,
func (r *IAMInstanceProfile) Remove(_ context.Context) error {
_, err := r.svc.DeleteInstanceProfile(&iam.DeleteInstanceProfileInput{
InstanceProfileName: r.Name,
})
if err != nil {
return err
Expand All @@ -98,20 +98,22 @@ func (e *IAMInstanceProfile) Remove(_ context.Context) error {
return nil
}

func (e *IAMInstanceProfile) String() string {
return e.name
func (r *IAMInstanceProfile) String() string {
return *r.Name
}

func (e *IAMInstanceProfile) Properties() types.Properties {
properties := types.NewProperties()
func (r *IAMInstanceProfile) Properties() types.Properties {
return types.NewPropertiesFromStruct(r)
}

for _, tagValue := range e.profile.Tags {
properties.SetTag(tagValue.Key, tagValue.Value)
// GetIAMInstanceProfile returns an IAM instance profile
func GetIAMInstanceProfile(svc iamiface.IAMAPI, instanceProfileName *string) (*iam.InstanceProfile, error) {
resp, err := svc.GetInstanceProfile(&iam.GetInstanceProfileInput{
InstanceProfileName: instanceProfileName,
})
if err != nil {
return nil, err
}

properties.
Set("Name", e.name).
Set("Path", e.path)

return properties
return resp.InstanceProfile, nil
}
123 changes: 123 additions & 0 deletions resources/iam-instance-profile_mock_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package resources

import (
"context"
"testing"
"time"

"github.com/golang/mock/gomock"
"github.com/gotidy/ptr"
"github.com/stretchr/testify/assert"

"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/iam"

"github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface"
"github.com/ekristen/aws-nuke/v3/pkg/nuke"
)

func Test_Mock_IAMInstanceProfile_List(t *testing.T) {
a := assert.New(t)
ctrl := gomock.NewController(t)
defer ctrl.Finish()

mockIAM := mock_iamiface.NewMockIAMAPI(ctrl)

instanceProfile := &iam.InstanceProfile{
Arn: ptr.String("arn:aws:iam::123456789012:instance-profile/profile:foobar"),
InstanceProfileName: ptr.String("profile:foobar"),
CreateDate: ptr.Time(time.Now()),
Roles: []*iam.Role{
{
Arn: ptr.String("arn:aws:iam::123456789012:role/role:foobar"),
RoleName: ptr.String("role:foobar"),
},
},
}

instanceProfile2 := &iam.InstanceProfile{
Arn: ptr.String("arn:aws:iam::123456789012:instance-profile/profile:foobar2"),
InstanceProfileName: ptr.String("profile:foobar2"),
CreateDate: ptr.Time(time.Now()),
Roles: []*iam.Role{
{
Arn: ptr.String("arn:aws:iam::123456789012:role/role:foobar2"),
RoleName: ptr.String("role:foobar2"),
},
},
}

mockIAM.EXPECT().ListInstanceProfiles(gomock.Any()).Return(&iam.ListInstanceProfilesOutput{
InstanceProfiles: []*iam.InstanceProfile{
instanceProfile,
instanceProfile2,
},
}, nil)

mockIAM.EXPECT().GetInstanceProfile(&iam.GetInstanceProfileInput{
InstanceProfileName: ptr.String("profile:foobar"),
}).Return(&iam.GetInstanceProfileOutput{
InstanceProfile: instanceProfile,
}, nil)

mockIAM.EXPECT().GetInstanceProfile(&iam.GetInstanceProfileInput{
InstanceProfileName: ptr.String("profile:foobar2"),
}).Return(nil, awserr.New("400", "InstanceProfileNotFound", nil))

lister := IAMInstanceProfileLister{
mockSvc: mockIAM,
}

resources, err := lister.List(context.TODO(), &nuke.ListerOpts{
Region: &nuke.Region{
Name: "us-east-2",
},
Session: session.Must(session.NewSession()),
})

a.Nil(err)
a.Len(resources, 1)
}

func Test_Mock_IAMInstanceProfile_Remove(t *testing.T) {
a := assert.New(t)
ctrl := gomock.NewController(t)
defer ctrl.Finish()

mockIAM := mock_iamiface.NewMockIAMAPI(ctrl)

iamInstanceProfile := IAMInstanceProfile{
svc: mockIAM,
Name: ptr.String("ip:foobar"),
Path: ptr.String("/"),
}

mockIAM.EXPECT().DeleteInstanceProfile(gomock.Eq(&iam.DeleteInstanceProfileInput{
InstanceProfileName: iamInstanceProfile.Name,
})).Return(&iam.DeleteInstanceProfileOutput{}, nil)

err := iamInstanceProfile.Remove(context.TODO())
a.Nil(err)
}

func Test_Mock_IAMInstanceProfile_Properties(t *testing.T) {
a := assert.New(t)

iamInstanceProfile := IAMInstanceProfile{
Name: ptr.String("ip:foobar"),
Path: ptr.String("/"),
Tags: []*iam.Tag{
{
Key: ptr.String("foo"),
Value: ptr.String("bar"),
},
},
}

a.Equal("ip:foobar", iamInstanceProfile.Properties().Get("Name"))
a.Equal("/", iamInstanceProfile.Properties().Get("Path"))
a.Equal("bar", iamInstanceProfile.Properties().Get("tag:foo"))

a.Equal("ip:foobar", iamInstanceProfile.String())
}
Loading

0 comments on commit ba4a553

Please sign in to comment.